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 class position_policy<senf::console::detail::FilePositionWithIndex>
301 : public position_policy<file_position>
304 typedef position_policy<file_position> Base;
306 void next_line(senf::console::detail::FilePositionWithIndex & pos)
308 Base::next_line(pos);
312 void next_char(senf::console::detail::FilePositionWithIndex & pos)
314 Base::next_char(pos);
318 void tabulation(senf::console::detail::FilePositionWithIndex & pos)
320 Base::tabulation(pos);
325 #if HAVE_BOOST_SPIRIT_INCLUDE_CLASSIC_HPP
330 prefix_ senf::console::CommandParser::CommandParser()
334 prefix_ senf::console::CommandParser::~CommandParser()
337 // This template member is placed here, since it is ONLY called from the implementation. Otherwise,
338 // we would need to expose the Impl member to the public, which we don't want to do.
340 template <class Iterator>
341 prefix_ Iterator senf::console::CommandParser::parseLoop(Iterator npb, Iterator npe,
342 std::string const & source, Callback cb)
344 typedef detail::boost_spirit::position_iterator<
345 Iterator, detail::FilePositionWithIndex> PositionIterator;
346 PositionIterator b (npb, npe, source);
347 PositionIterator e (npe, npe, source);
348 ParseCommandInfo info;
349 detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
350 detail::boost_spirit::parse_info<PositionIterator> result;
353 result = detail::boost_spirit::parse(
354 b, e, * impl().grammar.use_parser<Impl::Grammar::SkipParser>());
360 result = detail::boost_spirit::parse(b, e,
361 impl().grammar.use_parser<Impl::Grammar::CommandParser>(),
362 impl().grammar.use_parser<Impl::Grammar::SkipParser>());
364 catch (detail::boost_spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
365 if (impl().grammar.incremental && ex.where == e)
368 throwParserError(ex);
370 // Otherwise the error handling in the parser is broken
371 SENF_ASSERT( result.hit, "Internal parser failure (error handling broken?)" );
376 catch (senf::ExceptionMixin & ex) {
377 detail::FilePositionWithIndex pos (result.stop.get_position());
378 ex << "\nat " << pos.file << ":" << pos.line << ":" << pos.column;
385 prefix_ void senf::console::CommandParser::parse(std::string const & command, Callback cb)
387 parseLoop(command.begin(), command.end(), "<unknown>", cb);
390 prefix_ void senf::console::CommandParser::parseFile(std::string const & filename, Callback cb)
392 // file_iterator sets errno to EINVAL and returns error when file size is 0
393 // so we check the file size before
395 if (stat( filename.c_str(), &statBuf) != 0)
396 throw SystemException(filename, errno SENF_EXC_DEBUGINFO);
397 if (statBuf.st_size == 0) return;
398 detail::boost_spirit::file_iterator<> i (filename);
401 // hmm.. errno==0 but the file_iterator is false; something is wrong but we
402 // do not know what exactly, so we throw a SystemeException with EINVAL
403 throw SystemException(filename, EINVAL SENF_EXC_DEBUGINFO);
405 throw SystemException(filename, errno SENF_EXC_DEBUGINFO);
407 detail::boost_spirit::file_iterator<> const i_end (i.make_end());
408 parseLoop(i, i_end, filename, cb);
411 prefix_ void senf::console::CommandParser::parseArguments(std::string const & arguments,
412 ParseCommandInfo & info)
414 typedef detail::boost_spirit::position_iterator<
415 std::string::const_iterator, detail::FilePositionWithIndex> PositionIterator;
416 PositionIterator b (arguments.begin(), arguments.end(), std::string("<unknown>"));
417 PositionIterator e (arguments.end(), arguments.end(), std::string("<unknown>"));
418 detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
419 detail::boost_spirit::parse_info<PositionIterator> result;
421 result = detail::boost_spirit::parse( b, e,
422 impl().grammar.use_parser<Impl::Grammar::ArgumentsParser>(),
423 impl().grammar.use_parser<Impl::Grammar::SkipParser>() );
425 catch (detail::boost_spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
426 throwParserError(ex);
429 detail::FilePositionWithIndex pos (result.stop.get_position());
430 throw ParserErrorException("argument expected")
431 << "\nat " << pos.file << ":" << pos.line << ":" << pos.column;
435 prefix_ void senf::console::CommandParser::parsePath(std::string const & path,
436 ParseCommandInfo & info)
438 typedef detail::boost_spirit::position_iterator<
439 std::string::const_iterator, detail::FilePositionWithIndex> PositionIterator;
440 PositionIterator b (path.begin(), path.end(), std::string("<unknown>"));
441 PositionIterator e (path.end(), path.end(), std::string("<unknown>"));
442 detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
443 detail::boost_spirit::parse_info<PositionIterator> result;
445 result = detail::boost_spirit::parse( b, e,
446 impl().grammar.use_parser<Impl::Grammar::PathParser>(),
447 impl().grammar.use_parser<Impl::Grammar::SkipParser>() );
449 catch (detail::boost_spirit::parser_error<Impl::Grammar::Errors, PositionIterator> & ex) {
450 throwParserError(ex);
453 detail::FilePositionWithIndex pos (result.stop.get_position());
454 throw ParserErrorException("path expected")
455 << "\nat " << pos.file << ":" << pos.line << ":" << pos.column;
459 struct senf::console::CommandParser::SetIncremental
461 SetIncremental(CommandParser & parser) : parser_ (parser) {
462 parser_.impl().grammar.incremental = true;
466 parser_.impl().grammar.incremental = false;
469 CommandParser & parser_;
472 prefix_ std::string::size_type
473 senf::console::CommandParser::parseIncremental(std::string const & commands, Callback cb)
475 SetIncremental si (*this);
476 return std::distance( commands.begin(),
477 parseLoop(commands.begin(), commands.end(), "<unknown>", cb) );
480 //-/////////////////////////////////////////////////////////////////////////////////////////////////
483 prefix_ bool senf::console::CommandParser::isSpecialChar(char ch)
485 return Impl::Grammar::special_p().test(ch);
488 prefix_ bool senf::console::CommandParser::isPunctuationChar(char ch)
490 return Impl::Grammar::punctuation_p().test(ch);
493 prefix_ bool senf::console::CommandParser::isSpaceChar(char ch)
495 return Impl::Grammar::space_p().test(ch);
498 prefix_ bool senf::console::CommandParser::isInvalidChar(char ch)
500 return Impl::Grammar::invalid_p().test(ch);
503 prefix_ bool senf::console::CommandParser::isWordChar(char ch)
505 return Impl::Grammar::word_p().test(ch);
508 //-/////////////////////////////////////////////////////////////////////////////////////////////////
510 //#include "Parse.mpp"
516 // comment-column: 40
517 // c-file-style: "senf"
518 // indent-tabs-mode: nil
519 // ispell-local-dictionary: "american"
520 // compile-command: "scons -u test"