4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at
9 // http://senf.berlios.de/license.html
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on,
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
15 // Software distributed under the License is distributed on an "AS IS" basis,
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17 // for the specific language governing rights and limitations under the License.
19 // The Original Code is Fraunhofer FOKUS code.
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V.
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
26 // Stefan Bund <g0dil@berlios.de>
29 \brief Parse non-inline non-template implementation */
37 #include <boost/iterator/transform_iterator.hpp>
38 #include <senf/config.hh>
40 #if HAVE_BOOST_SPIRIT_INCLUDE_CLASSIC_HPP
41 # include <boost/spirit/include/classic_file_iterator.hpp>
42 # include <boost/spirit/include/classic_position_iterator.hpp>
44 # include <boost/spirit/iterator/file_iterator.hpp>
45 # include <boost/spirit/iterator/position_iterator.hpp>
48 #include <senf/Utils/Exception.hh>
49 #include <senf/Utils/senfassert.hh>
51 //#include "Parse.mpp"
53 //-/////////////////////////////////////////////////////////////////////////////////////////////////
61 struct ParseDispatcher
63 ParseCommandInfo * info_;
66 BindInfo( ParseDispatcher & d, ParseCommandInfo & info)
67 : dispatcher (d) { dispatcher.info_ = &info; }
68 ~BindInfo() { dispatcher.info_ = 0; }
70 ParseDispatcher & dispatcher;
73 void beginCommand(std::vector<Token> & command)
75 info_->command(command); }
80 void pushToken(Token const & token)
81 { info_->addToken(token); }
83 void builtin_cd(std::vector<Token> & path)
85 info_->builtin(ParseCommandInfo::BuiltinCD);
86 setBuiltinPathArg(path); }
88 void builtin_ls(std::vector<Token> & path)
90 info_->builtin(ParseCommandInfo::BuiltinLS);
91 setBuiltinPathArg(path); }
93 void builtin_ll(std::vector<Token> & path)
95 info_->builtin(ParseCommandInfo::BuiltinLL);
96 setBuiltinPathArg(path); }
98 void builtin_lr(std::vector<Token> & path)
100 info_->builtin(ParseCommandInfo::BuiltinLR);
101 setBuiltinPathArg(path); }
104 { // Do NOT call clear since pushDirectory is set in ADDITION
105 // to an ordinary command (which may be only a directory name)
106 info_->builtin(ParseCommandInfo::BuiltinPUSHD); }
110 info_->builtin(ParseCommandInfo::BuiltinPOPD); }
114 info_->builtin(ParseCommandInfo::BuiltinEXIT); }
116 void builtin_help(std::vector<Token> & path)
118 info_->builtin(ParseCommandInfo::BuiltinHELP);
119 setBuiltinPathArg(path); }
121 void setBuiltinPathArg(std::vector<Token> & path)
123 info_->command(path);
124 // pushToken(ArgumentGroupOpenToken());
125 // for (std::vector<Token>::const_iterator i (path.begin());
126 // i != path.end(); ++i)
128 // pushToken(ArgumentGroupCloseToken());
136 //-/////////////////////////////////////////////////////////////////////////////////////////////////
137 // senf::console::Token
139 prefix_ senf::console::Token::Token(TokenType type, std::string token,
140 detail::FilePositionWithIndex const & pos)
141 : type_(type), token_ (token), line_ (pos.line), column_ (pos.column), index_ (pos.index)
145 prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Token const & token)
147 static char const * tokenTypeName[] = {
151 "ArgumentGroupClose",
152 "DirectoryGroupOpen",
153 "DirectoryGroupClose",
159 // The real table is:
160 // static const int bitPosition[32] = {
161 // 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
162 // 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 };
163 // However, we have replaced all values >= sizeof(tokenTypeName) with 0
164 // and have added 1 to all the remaining values
165 static const int bitPosition[32] = {
166 1, 2, 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 9,
167 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 7, 0, 6, 0, 10 };
168 // We need to check token.type() against 0 explicitly since 0 and 1 will both be mapped to 0
169 os << tokenTypeName[ token.type()
170 ? bitPosition[(((token.type() & -token.type()) * 0x077CB531UL) >> 27) & 31]
178 //-/////////////////////////////////////////////////////////////////////////////////////////////////
179 // senf::console::ParseCommandInfo
181 prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
182 ParseCommandInfo const & info)
184 if (info.builtin() == ParseCommandInfo::NoBuiltin) {
185 ParseCommandInfo::TokensRange::const_iterator i (info.commandPath().begin());
186 ParseCommandInfo::TokensRange::const_iterator const i_end (info.commandPath().end());
189 stream << i->value();
190 if ( ++i != i_end ) stream << "/";
196 char const * builtins[] = { 0, "cd", "ls", "lr", "pushd", "popd", "exit", "help" };
197 stream << "builtin-" << builtins[info.builtin()];
200 ParseCommandInfo::ArgumentsRange args (info.arguments());
201 for (ParseCommandInfo::argument_iterator i (args.begin()); i != args.end(); ++i) {
202 ParseCommandInfo::token_iterator j (i->begin());
204 if ( j != i->end() ) {
206 stream << "'" << j->value() << "'";
207 if ( ++j != i->end() ) stream << ' ';
217 //-/////////////////////////////////////////////////////////////////////////////////////////////////
218 // senf::console::ParseCommandInfo::ArgumentIterator
220 prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::setRange()
223 if (b_->is(Token::ArgumentGroupOpen)) {
227 if (e_->is(Token::ArgumentGroupOpen))
229 else if (e_->is(Token::ArgumentGroupClose)) {
240 prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::decrement()
244 if (b_->is(Token::ArgumentGroupClose)) {
247 if (b_->is(Token::ArgumentGroupClose))
249 else if (b_->is(Token::ArgumentGroupOpen)) {
259 //-/////////////////////////////////////////////////////////////////////////////////////////////////
260 // senf::console::CommandParser
264 struct senf::console::CommandParser::Impl
266 typedef detail::CommandGrammar<detail::ParseDispatcher> Grammar;
268 detail::ParseDispatcher dispatcher;
269 Grammar::Context context;
272 Impl() : dispatcher(), context(), grammar(dispatcher, context) {}
279 template <class Error>
280 void throwParserError(Error const & err)
282 static char const * msg [] = { "end of statement expected",
286 senf::console::detail::FilePositionWithIndex pos (err.where.get_position());
287 throw senf::console::CommandParser::ParserErrorException(msg[err.descriptor])
288 << "\nat " << pos.file << ":" << pos.line << ":" << pos.column;
295 #if HAVE_BOOST_SPIRIT_INCLUDE_CLASSIC_HPP
300 struct position_policy<senf::console::detail::FilePositionWithIndex>
301 : public position_policy<file_position>
303 typedef position_policy<file_position> Base;
305 void next_line(senf::console::detail::FilePositionWithIndex & pos)
307 Base::next_line(pos);
311 void next_char(senf::console::detail::FilePositionWithIndex & pos)
313 Base::next_char(pos);
317 void tabulation(senf::console::detail::FilePositionWithIndex & pos)
319 Base::tabulation(pos);
324 #if HAVE_BOOST_SPIRIT_INCLUDE_CLASSIC_HPP
329 prefix_ senf::console::CommandParser::CommandParser()
333 prefix_ senf::console::CommandParser::~CommandParser()
336 // This template member is placed here, since it is ONLY called from the implementation. Otherwise,
337 // we would need to expose the Impl member to the public, which we don't want to do.
339 template <class Iterator>
340 prefix_ Iterator senf::console::CommandParser::parseLoop(Iterator npb, Iterator npe,
341 std::string const & source, Callback cb)
343 typedef detail::boost_spirit::position_iterator<
344 Iterator, detail::FilePositionWithIndex> PositionIterator;
345 PositionIterator b (npb, npe, source);
346 PositionIterator e (npe, npe, source);
347 ParseCommandInfo info;
348 detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
349 detail::boost_spirit::parse_info<PositionIterator> result;
352 result = detail::boost_spirit::parse(
353 b, e, * impl().grammar.use_parser<Impl::Grammar::SkipParser>());
359 result = detail::boost_spirit::parse(b, e,
360 impl().grammar.use_parser<Impl::Grammar::CommandParser>(),
361 impl().grammar.use_parser<Impl::Grammar::SkipParser>());
363 catch (detail::boost_spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
364 if (impl().grammar.incremental && ex.where == e)
367 throwParserError(ex);
369 // Otherwise the error handling in the parser is broken
370 SENF_ASSERT( result.hit, "Internal parser failure (error handling broken?)" );
375 catch (senf::ExceptionMixin & ex) {
376 detail::FilePositionWithIndex pos (result.stop.get_position());
377 ex << "\nat " << pos.file << ":" << pos.line << ":" << pos.column;
384 prefix_ void senf::console::CommandParser::parse(std::string const & command, Callback cb)
386 parseLoop(command.begin(), command.end(), "<unknown>", cb);
389 prefix_ void senf::console::CommandParser::parseFile(std::string const & filename, Callback cb)
391 // file_iterator sets errno to EINVAL and returns error when file size is 0
392 // so we check the file size before
394 if (stat( filename.c_str(), &statBuf) != 0)
395 throw SystemException(filename, errno SENF_EXC_DEBUGINFO);
396 if (statBuf.st_size == 0) return;
397 detail::boost_spirit::file_iterator<> i (filename);
400 // hmm.. errno==0 but the file_iterator is false; something is wrong but we
401 // do not know what exactly, so we throw a SystemeException with EINVAL
402 throw SystemException(filename, EINVAL SENF_EXC_DEBUGINFO);
404 throw SystemException(filename, errno SENF_EXC_DEBUGINFO);
406 detail::boost_spirit::file_iterator<> const i_end (i.make_end());
407 parseLoop(i, i_end, filename, cb);
410 prefix_ void senf::console::CommandParser::parseArguments(std::string const & arguments,
411 ParseCommandInfo & info)
413 typedef detail::boost_spirit::position_iterator<
414 std::string::const_iterator, detail::FilePositionWithIndex> PositionIterator;
415 PositionIterator b (arguments.begin(), arguments.end(), std::string("<unknown>"));
416 PositionIterator e (arguments.end(), arguments.end(), std::string("<unknown>"));
417 detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
418 detail::boost_spirit::parse_info<PositionIterator> result;
420 result = detail::boost_spirit::parse( b, e,
421 impl().grammar.use_parser<Impl::Grammar::ArgumentsParser>(),
422 impl().grammar.use_parser<Impl::Grammar::SkipParser>() );
424 catch (detail::boost_spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
425 throwParserError(ex);
428 detail::FilePositionWithIndex pos (result.stop.get_position());
429 throw ParserErrorException("argument expected")
430 << "\nat " << pos.file << ":" << pos.line << ":" << pos.column;
434 prefix_ void senf::console::CommandParser::parsePath(std::string const & path,
435 ParseCommandInfo & info)
437 typedef detail::boost_spirit::position_iterator<
438 std::string::const_iterator, detail::FilePositionWithIndex> PositionIterator;
439 PositionIterator b (path.begin(), path.end(), std::string("<unknown>"));
440 PositionIterator e (path.end(), path.end(), std::string("<unknown>"));
441 detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
442 detail::boost_spirit::parse_info<PositionIterator> result;
444 result = detail::boost_spirit::parse( b, e,
445 impl().grammar.use_parser<Impl::Grammar::PathParser>(),
446 impl().grammar.use_parser<Impl::Grammar::SkipParser>() );
448 catch (detail::boost_spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
449 throwParserError(ex);
452 detail::FilePositionWithIndex pos (result.stop.get_position());
453 throw ParserErrorException("path expected")
454 << "\nat " << pos.file << ":" << pos.line << ":" << pos.column;
458 struct senf::console::CommandParser::SetIncremental
460 SetIncremental(CommandParser & parser) : parser_ (parser) {
461 parser_.impl().grammar.incremental = true;
465 parser_.impl().grammar.incremental = false;
468 CommandParser & parser_;
471 prefix_ std::string::size_type
472 senf::console::CommandParser::parseIncremental(std::string const & commands, Callback cb)
474 SetIncremental si (*this);
475 return std::distance( commands.begin(),
476 parseLoop(commands.begin(), commands.end(), "<unknown>", cb) );
479 //-/////////////////////////////////////////////////////////////////////////////////////////////////
482 prefix_ bool senf::console::CommandParser::isSpecialChar(char ch)
484 return Impl::Grammar::special_p.test(ch);
487 prefix_ bool senf::console::CommandParser::isPunctuationChar(char ch)
489 return Impl::Grammar::punctuation_p.test(ch);
492 prefix_ bool senf::console::CommandParser::isSpaceChar(char ch)
494 return Impl::Grammar::space_p.test(ch);
497 prefix_ bool senf::console::CommandParser::isInvalidChar(char ch)
499 return Impl::Grammar::invalid_p.test(ch);
502 prefix_ bool senf::console::CommandParser::isWordChar(char ch)
504 return Impl::Grammar::word_p.test(ch);
507 //-/////////////////////////////////////////////////////////////////////////////////////////////////
509 //#include "Parse.mpp"
515 // comment-column: 40
516 // c-file-style: "senf"
517 // indent-tabs-mode: nil
518 // ispell-local-dictionary: "american"
519 // compile-command: "scons -u test"