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 pushDirectory(std::vector<Token> & path)
81 info_->builtin(ParseCommandInfo::BuiltinPUSHD);
82 setBuiltinPathArg(path); }
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)
99 pushToken(ArgumentGroupOpenToken());
100 for (std::vector<Token>::const_iterator i (path.begin());
101 i != path.end(); ++i)
103 pushToken(ArgumentGroupCloseToken());
111 ///////////////////////////////////////////////////////////////////////////
112 // senf::console::Token
114 prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Token const & token)
116 static char const * tokenTypeName[] = {
120 "ArgumentGroupClose",
121 "DirectoryGroupOpen",
122 "DirectoryGroupClose",
128 // The real table is:
129 // static const int bitPosition[32] = {
130 // 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
131 // 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 };
132 // However, we have replaced all values >= sizeof(tokenTypeName) with 0
133 // and have added 1 to all the remaining values
134 static const int bitPosition[32] = {
135 1, 2, 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 9,
136 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 7, 0, 6, 0, 10 };
137 // We need to check token.type() against 0 explicitly since 0 and 1 will both be mapped to 0
138 os << tokenTypeName[ token.type()
139 ? bitPosition[(((token.type() & -token.type()) * 0x077CB531UL) >> 27) & 31]
147 ///////////////////////////////////////////////////////////////////////////
148 // senf::console::ParseCommandInfo
150 prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
151 ParseCommandInfo const & info)
153 if (info.builtin() == ParseCommandInfo::NoBuiltin) {
154 ParseCommandInfo::TokensRange::const_iterator i (info.commandPath().begin());
155 ParseCommandInfo::TokensRange::const_iterator const i_end (info.commandPath().end());
158 stream << i->value();
159 if ( ++i != i_end ) stream << "/";
165 char const * builtins[] = { 0, "cd", "ls", "pushd", "popd", "exit", "help" };
166 stream << "builtin-" << builtins[info.builtin()];
169 ParseCommandInfo::ArgumentsRange args (info.arguments());
170 for (ParseCommandInfo::argument_iterator i (args.begin()); i != args.end(); ++i) {
171 ParseCommandInfo::token_iterator j (i->begin());
173 if ( j != i->end() ) {
175 stream << "'" << j->value() << "'";
176 if ( ++j != i->end() ) stream << ' ';
186 ///////////////////////////////////////////////////////////////////////////
187 // senf::console::ParseCommandInfo::ArgumentIterator
189 prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::setRange()
192 if (b_->is(Token::ArgumentGroupOpen)) {
196 if (e_->is(Token::ArgumentGroupOpen))
198 else if (e_->is(Token::ArgumentGroupClose)) {
209 prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::decrement()
213 if (b_->is(Token::ArgumentGroupClose)) {
216 if (b_->is(Token::ArgumentGroupClose))
218 else if (b_->is(Token::ArgumentGroupOpen)) {
228 ///////////////////////////////////////////////////////////////////////////
229 // senf::console::CommandParser
233 struct senf::console::CommandParser::Impl
235 typedef detail::CommandGrammar<detail::ParseDispatcher> Grammar;
237 detail::ParseDispatcher dispatcher;
238 Grammar::Context context;
241 Impl() : dispatcher(), context(), grammar(dispatcher, context) {}
248 template <class Error>
249 void throwParserError(Error const & err)
251 static char const * msg [] = { "end of statement expected",
252 "'{' or arguments 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"