4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 \brief Parse non-inline non-template implementation */
31 #include <boost/iterator/transform_iterator.hpp>
32 #include <boost/spirit/iterator/file_iterator.hpp>
33 #include <boost/spirit/iterator/position_iterator.hpp>
34 #include "../../Utils/Exception.hh"
35 #include "../../Utils/senfassert.hh"
37 //#include "Parse.mpp"
39 ///////////////////////////////cc.p////////////////////////////////////////
47 struct ParseDispatcher
49 ParseCommandInfo * info_;
52 BindInfo( ParseDispatcher & d, ParseCommandInfo & info)
53 : dispatcher (d) { dispatcher.info_ = &info; }
54 ~BindInfo() { dispatcher.info_ = 0; }
56 ParseDispatcher & dispatcher;
59 void beginCommand(std::vector<Token> & command)
61 info_->command(command); }
66 void pushToken(Token const & token)
67 { info_->addToken(token); }
69 void builtin_cd(std::vector<Token> & path)
71 info_->builtin(ParseCommandInfo::BuiltinCD);
72 setBuiltinPathArg(path); }
74 void builtin_ls(std::vector<Token> & path)
76 info_->builtin(ParseCommandInfo::BuiltinLS);
77 setBuiltinPathArg(path); }
80 { // Do NOT call clear since pushDirectory is set in ADDITION
81 // to an ordinary command (which may be only a directory name)
82 info_->builtin(ParseCommandInfo::BuiltinPUSHD); }
86 info_->builtin(ParseCommandInfo::BuiltinPOPD); }
90 info_->builtin(ParseCommandInfo::BuiltinEXIT); }
92 void builtin_help(std::vector<Token> & path)
94 info_->builtin(ParseCommandInfo::BuiltinHELP);
95 setBuiltinPathArg(path); }
97 void setBuiltinPathArg(std::vector<Token> & path)
100 // pushToken(ArgumentGroupOpenToken());
101 // for (std::vector<Token>::const_iterator i (path.begin());
102 // i != path.end(); ++i)
104 // pushToken(ArgumentGroupCloseToken());
112 ///////////////////////////////////////////////////////////////////////////
113 // senf::console::Token
115 prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Token const & token)
117 static char const * tokenTypeName[] = {
121 "ArgumentGroupClose",
122 "DirectoryGroupOpen",
123 "DirectoryGroupClose",
129 // The real table is:
130 // static const int bitPosition[32] = {
131 // 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
132 // 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 };
133 // However, we have replaced all values >= sizeof(tokenTypeName) with 0
134 // and have added 1 to all the remaining values
135 static const int bitPosition[32] = {
136 1, 2, 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 9,
137 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 7, 0, 6, 0, 10 };
138 // We need to check token.type() against 0 explicitly since 0 and 1 will both be mapped to 0
139 os << tokenTypeName[ token.type()
140 ? bitPosition[(((token.type() & -token.type()) * 0x077CB531UL) >> 27) & 31]
148 ///////////////////////////////////////////////////////////////////////////
149 // senf::console::ParseCommandInfo
151 prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
152 ParseCommandInfo const & info)
154 if (info.builtin() == ParseCommandInfo::NoBuiltin) {
155 ParseCommandInfo::TokensRange::const_iterator i (info.commandPath().begin());
156 ParseCommandInfo::TokensRange::const_iterator const i_end (info.commandPath().end());
159 stream << i->value();
160 if ( ++i != i_end ) stream << "/";
166 char const * builtins[] = { 0, "cd", "ls", "pushd", "popd", "exit", "help" };
167 stream << "builtin-" << builtins[info.builtin()];
170 ParseCommandInfo::ArgumentsRange args (info.arguments());
171 for (ParseCommandInfo::argument_iterator i (args.begin()); i != args.end(); ++i) {
172 ParseCommandInfo::token_iterator j (i->begin());
174 if ( j != i->end() ) {
176 stream << "'" << j->value() << "'";
177 if ( ++j != i->end() ) stream << ' ';
187 ///////////////////////////////////////////////////////////////////////////
188 // senf::console::ParseCommandInfo::ArgumentIterator
190 prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::setRange()
193 if (b_->is(Token::ArgumentGroupOpen)) {
197 if (e_->is(Token::ArgumentGroupOpen))
199 else if (e_->is(Token::ArgumentGroupClose)) {
210 prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::decrement()
214 if (b_->is(Token::ArgumentGroupClose)) {
217 if (b_->is(Token::ArgumentGroupClose))
219 else if (b_->is(Token::ArgumentGroupOpen)) {
229 ///////////////////////////////////////////////////////////////////////////
230 // senf::console::CommandParser
234 struct senf::console::CommandParser::Impl
236 typedef detail::CommandGrammar<detail::ParseDispatcher> Grammar;
238 detail::ParseDispatcher dispatcher;
239 Grammar::Context context;
242 Impl() : dispatcher(), context(), grammar(dispatcher, context) {}
249 template <class Error>
250 void throwParserError(Error const & err)
252 static char const * msg [] = { "end of statement expected",
256 boost::spirit::file_position pos (err.where.get_position());
257 throw senf::console::CommandParser::ParserErrorException(msg[err.descriptor])
258 << "\nat " << pos.file << ":" << pos.line << ":" << pos.column;
262 prefix_ senf::console::CommandParser::CommandParser()
266 prefix_ senf::console::CommandParser::~CommandParser()
269 // This template member is placed here, since it is ONLY called from the implementation. Otherwise,
270 // we would need to expose the Impl member to the public, which we don't want to do.
272 template <class Iterator>
273 prefix_ Iterator senf::console::CommandParser::parseLoop(Iterator npb, Iterator npe,
274 std::string const & source, Callback cb)
276 typedef boost::spirit::position_iterator<Iterator> PositionIterator;
277 PositionIterator b (npb, npe, source);
278 PositionIterator e (npe, npe, source);
279 ParseCommandInfo info;
280 detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
281 boost::spirit::parse_info<PositionIterator> result;
284 result = boost::spirit::parse(
285 b, e, * impl().grammar.use_parser<Impl::Grammar::SkipParser>());
291 result = boost::spirit::parse(b, e,
292 impl().grammar.use_parser<Impl::Grammar::CommandParser>(),
293 impl().grammar.use_parser<Impl::Grammar::SkipParser>());
295 catch (boost::spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
296 if (impl().grammar.incremental && ex.where == e)
299 throwParserError(ex);
301 // Otherwise the error handling in the parser is broken
302 SENF_ASSERT( result.hit );
307 catch (senf::ExceptionMixin & ex) {
308 boost::spirit::file_position pos (result.stop.get_position());
309 ex << "\nat " << pos.file << ":" << pos.line << ":" << pos.column;
316 prefix_ void senf::console::CommandParser::parse(std::string const & command, Callback cb)
318 parseLoop(command.begin(), command.end(), "<unknown>", cb);
321 prefix_ void senf::console::CommandParser::parseFile(std::string const & filename, Callback cb)
323 boost::spirit::file_iterator<> i (filename);
324 if (!i) throw SystemException(ENOENT SENF_EXC_DEBUGINFO);
325 boost::spirit::file_iterator<> const i_end (i.make_end());
326 parseLoop(i, i_end, filename, cb);
329 prefix_ void senf::console::CommandParser::parseArguments(std::string const & arguments,
330 ParseCommandInfo & info)
332 typedef boost::spirit::position_iterator<std::string::const_iterator> PositionIterator;
333 PositionIterator b (arguments.begin(), arguments.end(), std::string("<unknown>"));
334 PositionIterator e (arguments.end(), arguments.end(), std::string("<unknown>"));
335 detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
336 boost::spirit::parse_info<PositionIterator> result;
338 result = boost::spirit::parse( b, e,
339 impl().grammar.use_parser<Impl::Grammar::ArgumentsParser>(),
340 impl().grammar.use_parser<Impl::Grammar::SkipParser>() );
342 catch (boost::spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
343 throwParserError(ex);
346 boost::spirit::file_position pos (result.stop.get_position());
347 throw ParserErrorException("argument expected")
348 << "\nat " << pos.file << ":" << pos.line << ":" << pos.column;
352 prefix_ void senf::console::CommandParser::parsePath(std::string const & path,
353 ParseCommandInfo & info)
355 typedef boost::spirit::position_iterator<std::string::const_iterator> PositionIterator;
356 PositionIterator b (path.begin(), path.end(), std::string("<unknown>"));
357 PositionIterator e (path.end(), path.end(), std::string("<unknown>"));
358 detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
359 boost::spirit::parse_info<PositionIterator> result;
361 result = boost::spirit::parse( b, e,
362 impl().grammar.use_parser<Impl::Grammar::PathParser>(),
363 impl().grammar.use_parser<Impl::Grammar::SkipParser>() );
365 catch (boost::spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
366 throwParserError(ex);
369 boost::spirit::file_position pos (result.stop.get_position());
370 throw ParserErrorException("path expected")
371 << "\nat " << pos.file << ":" << pos.line << ":" << pos.column;
375 struct senf::console::CommandParser::SetIncremental
377 SetIncremental(CommandParser & parser) : parser_ (parser) {
378 parser_.impl().grammar.incremental = true;
382 parser_.impl().grammar.incremental = false;
385 CommandParser & parser_;
388 prefix_ std::string::size_type
389 senf::console::CommandParser::parseIncremental(std::string const & commands, Callback cb)
391 SetIncremental si (*this);
392 return std::distance( commands.begin(),
393 parseLoop(commands.begin(), commands.end(), "<unknown>", cb) );
396 ///////////////////////////////cc.e////////////////////////////////////////
398 //#include "Parse.mpp"
404 // comment-column: 40
405 // c-file-style: "senf"
406 // indent-tabs-mode: nil
407 // ispell-local-dictionary: "american"
408 // compile-command: "scons -u test"