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); }
79 void builtin_ll(std::vector<Token> & path)
81 info_->builtin(ParseCommandInfo::BuiltinLL);
82 setBuiltinPathArg(path); }
84 void builtin_lr(std::vector<Token> & path)
86 info_->builtin(ParseCommandInfo::BuiltinLR);
87 setBuiltinPathArg(path); }
90 { // Do NOT call clear since pushDirectory is set in ADDITION
91 // to an ordinary command (which may be only a directory name)
92 info_->builtin(ParseCommandInfo::BuiltinPUSHD); }
96 info_->builtin(ParseCommandInfo::BuiltinPOPD); }
100 info_->builtin(ParseCommandInfo::BuiltinEXIT); }
102 void builtin_help(std::vector<Token> & path)
104 info_->builtin(ParseCommandInfo::BuiltinHELP);
105 setBuiltinPathArg(path); }
107 void setBuiltinPathArg(std::vector<Token> & path)
109 info_->command(path);
110 // pushToken(ArgumentGroupOpenToken());
111 // for (std::vector<Token>::const_iterator i (path.begin());
112 // i != path.end(); ++i)
114 // pushToken(ArgumentGroupCloseToken());
122 ///////////////////////////////////////////////////////////////////////////
123 // senf::console::Token
125 prefix_ senf::console::Token::Token(TokenType type, std::string token,
126 detail::FilePositionWithIndex const & pos)
127 : type_(type), token_ (token), line_ (pos.line), column_ (pos.column), index_ (pos.index)
131 prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Token const & token)
133 static char const * tokenTypeName[] = {
137 "ArgumentGroupClose",
138 "DirectoryGroupOpen",
139 "DirectoryGroupClose",
145 // The real table is:
146 // static const int bitPosition[32] = {
147 // 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
148 // 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 };
149 // However, we have replaced all values >= sizeof(tokenTypeName) with 0
150 // and have added 1 to all the remaining values
151 static const int bitPosition[32] = {
152 1, 2, 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 9,
153 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 7, 0, 6, 0, 10 };
154 // We need to check token.type() against 0 explicitly since 0 and 1 will both be mapped to 0
155 os << tokenTypeName[ token.type()
156 ? bitPosition[(((token.type() & -token.type()) * 0x077CB531UL) >> 27) & 31]
164 ///////////////////////////////////////////////////////////////////////////
165 // senf::console::ParseCommandInfo
167 prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
168 ParseCommandInfo const & info)
170 if (info.builtin() == ParseCommandInfo::NoBuiltin) {
171 ParseCommandInfo::TokensRange::const_iterator i (info.commandPath().begin());
172 ParseCommandInfo::TokensRange::const_iterator const i_end (info.commandPath().end());
175 stream << i->value();
176 if ( ++i != i_end ) stream << "/";
182 char const * builtins[] = { 0, "cd", "ls", "lr", "pushd", "popd", "exit", "help" };
183 stream << "builtin-" << builtins[info.builtin()];
186 ParseCommandInfo::ArgumentsRange args (info.arguments());
187 for (ParseCommandInfo::argument_iterator i (args.begin()); i != args.end(); ++i) {
188 ParseCommandInfo::token_iterator j (i->begin());
190 if ( j != i->end() ) {
192 stream << "'" << j->value() << "'";
193 if ( ++j != i->end() ) stream << ' ';
203 ///////////////////////////////////////////////////////////////////////////
204 // senf::console::ParseCommandInfo::ArgumentIterator
206 prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::setRange()
209 if (b_->is(Token::ArgumentGroupOpen)) {
213 if (e_->is(Token::ArgumentGroupOpen))
215 else if (e_->is(Token::ArgumentGroupClose)) {
226 prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::decrement()
230 if (b_->is(Token::ArgumentGroupClose)) {
233 if (b_->is(Token::ArgumentGroupClose))
235 else if (b_->is(Token::ArgumentGroupOpen)) {
245 ///////////////////////////////////////////////////////////////////////////
246 // senf::console::CommandParser
250 struct senf::console::CommandParser::Impl
252 typedef detail::CommandGrammar<detail::ParseDispatcher> Grammar;
254 detail::ParseDispatcher dispatcher;
255 Grammar::Context context;
258 Impl() : dispatcher(), context(), grammar(dispatcher, context) {}
265 template <class Error>
266 void throwParserError(Error const & err)
268 static char const * msg [] = { "end of statement expected",
272 senf::console::detail::FilePositionWithIndex pos (err.where.get_position());
273 throw senf::console::CommandParser::ParserErrorException(msg[err.descriptor])
274 << "\nat " << pos.file << ":" << pos.line << ":" << pos.column;
283 struct position_policy<senf::console::detail::FilePositionWithIndex>
284 : public position_policy<file_position>
286 typedef position_policy<file_position> Base;
288 void next_line(senf::console::detail::FilePositionWithIndex & pos)
290 Base::next_line(pos);
294 void next_char(senf::console::detail::FilePositionWithIndex & pos)
296 Base::next_char(pos);
300 void tabulation(senf::console::detail::FilePositionWithIndex & pos)
302 Base::tabulation(pos);
309 prefix_ senf::console::CommandParser::CommandParser()
313 prefix_ senf::console::CommandParser::~CommandParser()
316 // This template member is placed here, since it is ONLY called from the implementation. Otherwise,
317 // we would need to expose the Impl member to the public, which we don't want to do.
319 template <class Iterator>
320 prefix_ Iterator senf::console::CommandParser::parseLoop(Iterator npb, Iterator npe,
321 std::string const & source, Callback cb)
323 typedef boost::spirit::position_iterator<
324 Iterator, detail::FilePositionWithIndex> PositionIterator;
325 PositionIterator b (npb, npe, source);
326 PositionIterator e (npe, npe, source);
327 ParseCommandInfo info;
328 detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
329 boost::spirit::parse_info<PositionIterator> result;
332 result = boost::spirit::parse(
333 b, e, * impl().grammar.use_parser<Impl::Grammar::SkipParser>());
339 result = boost::spirit::parse(b, e,
340 impl().grammar.use_parser<Impl::Grammar::CommandParser>(),
341 impl().grammar.use_parser<Impl::Grammar::SkipParser>());
343 catch (boost::spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
344 if (impl().grammar.incremental && ex.where == e)
347 throwParserError(ex);
349 // Otherwise the error handling in the parser is broken
350 SENF_ASSERT( result.hit );
355 catch (senf::ExceptionMixin & ex) {
356 detail::FilePositionWithIndex pos (result.stop.get_position());
357 ex << "\nat " << pos.file << ":" << pos.line << ":" << pos.column;
364 prefix_ void senf::console::CommandParser::parse(std::string const & command, Callback cb)
366 parseLoop(command.begin(), command.end(), "<unknown>", cb);
369 prefix_ void senf::console::CommandParser::parseFile(std::string const & filename, Callback cb)
371 boost::spirit::file_iterator<> i (filename);
372 if (!i) throw SystemException(ENOENT SENF_EXC_DEBUGINFO);
373 boost::spirit::file_iterator<> const i_end (i.make_end());
374 parseLoop(i, i_end, filename, cb);
377 prefix_ void senf::console::CommandParser::parseArguments(std::string const & arguments,
378 ParseCommandInfo & info)
380 typedef boost::spirit::position_iterator<
381 std::string::const_iterator, detail::FilePositionWithIndex> PositionIterator;
382 PositionIterator b (arguments.begin(), arguments.end(), std::string("<unknown>"));
383 PositionIterator e (arguments.end(), arguments.end(), std::string("<unknown>"));
384 detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
385 boost::spirit::parse_info<PositionIterator> result;
387 result = boost::spirit::parse( b, e,
388 impl().grammar.use_parser<Impl::Grammar::ArgumentsParser>(),
389 impl().grammar.use_parser<Impl::Grammar::SkipParser>() );
391 catch (boost::spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
392 throwParserError(ex);
395 detail::FilePositionWithIndex pos (result.stop.get_position());
396 throw ParserErrorException("argument expected")
397 << "\nat " << pos.file << ":" << pos.line << ":" << pos.column;
401 prefix_ void senf::console::CommandParser::parsePath(std::string const & path,
402 ParseCommandInfo & info)
404 typedef boost::spirit::position_iterator<
405 std::string::const_iterator, detail::FilePositionWithIndex> PositionIterator;
406 PositionIterator b (path.begin(), path.end(), std::string("<unknown>"));
407 PositionIterator e (path.end(), path.end(), std::string("<unknown>"));
408 detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
409 boost::spirit::parse_info<PositionIterator> result;
411 result = boost::spirit::parse( b, e,
412 impl().grammar.use_parser<Impl::Grammar::PathParser>(),
413 impl().grammar.use_parser<Impl::Grammar::SkipParser>() );
415 catch (boost::spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
416 throwParserError(ex);
419 detail::FilePositionWithIndex pos (result.stop.get_position());
420 throw ParserErrorException("path expected")
421 << "\nat " << pos.file << ":" << pos.line << ":" << pos.column;
425 struct senf::console::CommandParser::SetIncremental
427 SetIncremental(CommandParser & parser) : parser_ (parser) {
428 parser_.impl().grammar.incremental = true;
432 parser_.impl().grammar.incremental = false;
435 CommandParser & parser_;
438 prefix_ std::string::size_type
439 senf::console::CommandParser::parseIncremental(std::string const & commands, Callback cb)
441 SetIncremental si (*this);
442 return std::distance( commands.begin(),
443 parseLoop(commands.begin(), commands.end(), "<unknown>", cb) );
446 ///////////////////////////////////////////////////////////////////////////
449 prefix_ bool senf::console::CommandParser::isSpecialChar(char ch)
451 return Impl::Grammar::special_p.test(ch);
454 prefix_ bool senf::console::CommandParser::isPunctuationChar(char ch)
456 return Impl::Grammar::punctuation_p.test(ch);
459 prefix_ bool senf::console::CommandParser::isSpaceChar(char ch)
461 return Impl::Grammar::space_p.test(ch);
464 prefix_ bool senf::console::CommandParser::isInvalidChar(char ch)
466 return Impl::Grammar::invalid_p.test(ch);
469 prefix_ bool senf::console::CommandParser::isWordChar(char ch)
471 return Impl::Grammar::word_p.test(ch);
474 /////////////////////////////cc.e////////////////////////////////////////
476 //#include "Parse.mpp"
482 // comment-column: 40
483 // c-file-style: "senf"
484 // indent-tabs-mode: nil
485 // ispell-local-dictionary: "american"
486 // compile-command: "scons -u test"