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 "../Utils/Exception.hh"
35 //#include "Parse.mpp"
37 ///////////////////////////////cc.p////////////////////////////////////////
45 struct ParseDispatcher
47 ParseCommandInfo * info_;
50 BindInfo( ParseDispatcher & d, ParseCommandInfo & info)
51 : dispatcher (d) { dispatcher.info_ = &info; }
52 ~BindInfo() { dispatcher.info_ = 0; }
54 ParseDispatcher & dispatcher;
57 void beginCommand(std::vector<Token> & command)
59 info_->command(command); }
64 void pushToken(Token const & token)
65 { info_->addToken(token); }
67 void builtin_cd(std::vector<Token> & path)
69 info_->builtin(ParseCommandInfo::BuiltinCD);
70 setBuiltinPathArg(path); }
72 void builtin_ls(std::vector<Token> & path)
74 info_->builtin(ParseCommandInfo::BuiltinLS);
75 setBuiltinPathArg(path); }
77 void pushDirectory(std::vector<Token> & path)
79 info_->builtin(ParseCommandInfo::BuiltinPUSHD);
80 setBuiltinPathArg(path); }
84 info_->builtin(ParseCommandInfo::BuiltinPOPD); }
88 info_->builtin(ParseCommandInfo::BuiltinEXIT); }
90 void builtin_help(std::vector<Token> & path)
92 info_->builtin(ParseCommandInfo::BuiltinHELP);
93 setBuiltinPathArg(path); }
95 void setBuiltinPathArg(std::vector<Token> & path)
97 pushToken(ArgumentGroupOpenToken());
98 for (std::vector<Token>::const_iterator i (path.begin());
101 pushToken(ArgumentGroupCloseToken());
109 ///////////////////////////////////////////////////////////////////////////
110 // senf::console::Token
112 prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Token const & token)
114 static char const * tokenTypeName[] = {
118 "ArgumentGroupClose",
119 "DirectoryGroupOpen",
120 "DirectoryGroupClose",
126 // The real table is:
127 // static const int bitPosition[32] = {
128 // 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
129 // 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 };
130 // However, we have replaced all values >= sizeof(tokenTypeName) with 0
131 // and have added 1 to all the remaining values
132 static const int bitPosition[32] = {
133 1, 2, 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 5, 9,
134 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 7, 0, 6, 0, 10 };
135 // We need to check token.type() against 0 explicitly since 0 and 1 will both be mapped to 0
136 os << tokenTypeName[ token.type()
137 ? bitPosition[((token.type() & -token.type()) * 0x077CB531UL) >> 27]
145 ///////////////////////////////////////////////////////////////////////////
146 // senf::console::ParseCommandInfo
148 prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
149 ParseCommandInfo const & info)
151 if (info.builtin() == ParseCommandInfo::NoBuiltin) {
152 ParseCommandInfo::TokensRange::const_iterator i (info.commandPath().begin());
153 ParseCommandInfo::TokensRange::const_iterator const i_end (info.commandPath().end());
156 stream << i->value();
157 if ( ++i != i_end ) stream << "/";
163 char const * builtins[] = { 0, "cd", "ls", "pushd", "popd", "exit", "help" };
164 stream << "builtin-" << builtins[info.builtin()];
167 ParseCommandInfo::ArgumentsRange args (info.arguments());
168 for (ParseCommandInfo::argument_iterator i (args.begin()); i != args.end(); ++i) {
169 ParseCommandInfo::token_iterator j (i->begin());
171 if ( j != i->end() ) {
173 stream << "'" << j->value() << "'";
174 if ( ++j != i->end() ) stream << ' ';
184 ///////////////////////////////////////////////////////////////////////////
185 // senf::console::ParseCommandInfo::ArgumentIterator
187 prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::setRange()
190 if (b_->is(Token::ArgumentGroupOpen)) {
194 if (e_->is(Token::ArgumentGroupOpen))
196 else if (e_->is(Token::ArgumentGroupClose)) {
207 prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::decrement()
211 if (b_->is(Token::ArgumentGroupClose)) {
214 if (b_->is(Token::ArgumentGroupClose))
216 else if (b_->is(Token::ArgumentGroupOpen)) {
226 ///////////////////////////////////////////////////////////////////////////
227 // senf::console::CommandParser
231 struct senf::console::CommandParser::Impl
233 typedef detail::CommandGrammar<detail::ParseDispatcher> Grammar;
235 detail::ParseDispatcher dispatcher;
236 Grammar::Context context;
239 Impl() : dispatcher(), context(), grammar(dispatcher, context) {}
244 prefix_ senf::console::CommandParser::CommandParser()
248 prefix_ senf::console::CommandParser::~CommandParser()
251 // This template member is placed here, since it is ONLY called from the implementation. Otherwise,
252 // we would need to expose the Impl member to the public, which we don't want to do.
254 template <class Iterator>
255 prefix_ Iterator senf::console::CommandParser::parseLoop(Iterator b, Iterator e, Callback cb)
257 ParseCommandInfo info;
258 detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
259 boost::spirit::parse_info<Iterator> result;
262 result = boost::spirit::parse(
263 b, e, * impl().grammar.use_parser<Impl::Grammar::SkipParser>());
268 result = boost::spirit::parse(b, e,
269 impl().grammar.use_parser<Impl::Grammar::CommandParser>(),
270 impl().grammar.use_parser<Impl::Grammar::SkipParser>());
279 prefix_ bool senf::console::CommandParser::parse(std::string const & command, Callback cb)
281 return parseLoop(command.begin(), command.end(), cb) == command.end();
284 prefix_ bool senf::console::CommandParser::parseFile(std::string const & filename, Callback cb)
286 boost::spirit::file_iterator<> i (filename);
287 if (!i) throw SystemException(ENOENT SENF_EXC_DEBUGINFO);
288 boost::spirit::file_iterator<> const i_end (i.make_end());
290 return parseLoop(i, i_end, cb) == i_end;
293 prefix_ bool senf::console::CommandParser::parseArguments(std::string const & arguments,
294 ParseCommandInfo & info)
296 detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
297 return boost::spirit::parse( arguments.begin(), arguments.end(),
298 impl().grammar.use_parser<Impl::Grammar::ArgumentsParser>(),
299 impl().grammar.use_parser<Impl::Grammar::SkipParser>()
303 struct senf::console::CommandParser::SetIncremental
305 SetIncremental(CommandParser & parser) : parser_ (parser) {
306 parser_.impl().grammar.incremental = true;
310 parser_.impl().grammar.incremental = false;
313 CommandParser & parser_;
316 prefix_ std::string::size_type
317 senf::console::CommandParser::parseIncremental(std::string const & commands, Callback cb)
319 SetIncremental si (*this);
320 return std::distance( commands.begin(),
321 parseLoop(commands.begin(), commands.end(), cb) );
324 ///////////////////////////////////////////////////////////////////////////
325 // senf::console::SyntaxErrorException
327 prefix_ char const * senf::console::SyntaxErrorException::what()
330 return message().empty() ? "syntax error" : message().c_str();
333 ///////////////////////////////cc.e////////////////////////////////////////
335 //#include "Parse.mpp"
341 // comment-column: 40
342 // c-file-style: "senf"
343 // indent-tabs-mode: nil
344 // ispell-local-dictionary: "american"
345 // compile-command: "scons -u test"