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 internal header */
31 #include <boost/regex.hpp>
32 #include <boost/spirit.hpp>
33 #include <boost/spirit/utility/grammar_def.hpp>
34 #include <boost/spirit/actor.hpp>
35 #include <boost/spirit/dynamic.hpp>
36 #include <boost/spirit/phoenix.hpp>
37 #include <boost/bind.hpp>
38 #include <boost/function.hpp>
39 #include <boost/ref.hpp>
41 ///////////////////////////////ih.p////////////////////////////////////////
49 ///////////////////////////////////////////////////////////////////////////
54 template <class T, class Value>
55 void act(T & ref, Value const & value) const
56 { ref += T(1, value); }
58 template <class T, class Iterator>
59 void act(T & ref, Iterator const & f, Iterator const & l) const
64 inline boost::spirit::ref_value_actor<T, append_action>
66 { return boost::spirit::ref_value_actor<T, append_action>(ref); }
68 template <class T, class Value>
69 inline boost::spirit::ref_const_ref_actor<T, Value, append_action>
70 append_a(T & ref, Value const & value)
71 { return boost::spirit::ref_const_ref_actor<T, Value, append_action>(ref, value); }
73 ///////////////////////////////////////////////////////////////////////////
76 template <class ParseDispatcher>
77 struct CommandGrammar : boost::spirit::grammar<CommandGrammar<ParseDispatcher> >
79 ///////////////////////////////////////////////////////////////////////////
82 enum { CommandParser, SkipParser, ArgumentsParser };
84 ///////////////////////////////////////////////////////////////////////////
85 // The parse context (variables needed while parsing)
87 typedef Token::TokenType TokenType;
91 std::vector<Token> path;
95 // OUCH ... This is sooooo stupid .. push_back_a and assign_a take their
96 // arguments by const-reference and STORE the REFERENCE ... they do NOT accept
97 // literal values !!!!!!
98 static const Token EmptyToken;
103 ///////////////////////////////////////////////////////////////////////////
108 ///////////////////////////////////////////////////////////////////////////
109 // Dispatching semantic actions
111 ParseDispatcher & dispatcher;
113 struct Dispatch_actor
115 Dispatch_actor(boost::function<void ()> fn_) : fn (fn_) {}
117 template <class Value>
118 void operator()(Value const & value) const
121 template <class Iterator>
122 void operator()(Iterator const & f, Iterator const & l) const
125 boost::function<void ()> fn;
128 template <class Callback>
129 Dispatch_actor dispatch(Callback cb) const
130 { return Dispatch_actor(boost::bind(cb, boost::ref(dispatcher))); }
132 template <class Callback, class Arg>
133 Dispatch_actor dispatch(Callback cb, Arg const & arg) const
134 { return Dispatch_actor(boost::bind(cb, boost::ref(dispatcher), arg)); }
136 template <class Callback, class Arg1, class Arg2>
137 Dispatch_actor dispatch(Callback cb, Arg1 const & arg1, Arg2 const & arg2) const
138 { return Dispatch_actor(boost::bind(cb, boost::ref(dispatcher), arg1, arg2)); }
140 struct TokenSetter_actor
142 TokenSetter_actor(Context & c, TokenType t) : c_ (c), t_ (t) {}
144 void operator()(std::string const & value) const
145 { c_.token = Token(t_, value); }
146 void operator()(char value) const
147 { c_.token = Token(t_, std::string(1,value)); }
148 template <class Iterator> void operator()(Iterator const & f, Iterator const & l) const
149 { c_.token = Token(t_, std::string(f,l)); }
155 struct TokenSetter_value_actor
156 : public TokenSetter_actor
158 TokenSetter_value_actor(Context & c, TokenType t, std::string & v)
159 : TokenSetter_actor(c,t), v_ (v) {}
161 template <class Value> void operator()(Value const &) const
162 { TokenSetter_actor::operator()(v_); }
164 template <class Iterator> void operator()(Iterator const &, Iterator const &) const
165 { TokenSetter_actor::operator()(v_); }
170 TokenSetter_actor set_token_a(TokenType t) const
171 { return TokenSetter_actor(context, t); }
173 TokenSetter_value_actor set_token_a(TokenType t, std::string & arg) const
174 { return TokenSetter_value_actor(context, t, arg); }
176 ///////////////////////////////////////////////////////////////////////////
178 CommandGrammar(ParseDispatcher & d, Context & c)
179 : context(c), incremental(false), dispatcher(d) {}
181 template <class Scanner>
183 : public boost::spirit::grammar_def< boost::spirit::rule<Scanner>,
184 boost::spirit::rule<Scanner>,
185 boost::spirit::rule<Scanner> >
187 boost::spirit::rule<Scanner> command, path, argument, word, string, hexstring, token,
188 punctuation, hexbyte, balanced_tokens, simple_argument, complex_argument, builtin,
189 skip, statement, relpath, abspath, arguments, group_start, group_close,
191 boost::spirit::chset<> special_p, punctuation_p, space_p, invalid_p, word_p;
192 boost::spirit::distinct_parser<> keyword_p;
194 definition(CommandGrammar const & self) :
196 // Characters with a special meaning within the parser
197 special_p ("/(){};"),
199 // Additional characters which are returned as punctuation tokens
200 // (only allowed within '()').
201 punctuation_p (",="),
203 // Whitespace characters
206 // Invalid characters: All chars below \x20 (space) which are not space_p
207 // (don't put a \0 in the chset<> argument *string* ...)
209 boost::spirit::chset<>('\0') | boost::spirit::chset<>("\x01-\x20") - space_p ),
211 // Valid word characters
213 boost::spirit::anychar_p - special_p - punctuation_p - space_p - invalid_p),
215 // Keywords must not be followed by a word char or '/'
216 keyword_p ( word_p | boost::spirit::ch_p('/') )
219 using namespace boost::spirit;
220 using namespace phoenix;
221 typedef ParseDispatcher PD;
224 ///////////////////////////////////////////////////////////////////
228 // This is EBNF with some minor tweaks to accommodate C++ syntax
230 // * a any number of a's
231 // + a at least one a
233 // a >> b a followed by b
235 // a % b any number of a's separated by b's
238 // Beside this, we use some special parsers (ch_p, eps_p, confix_p, lex_escape_ch_p,
239 // keyword_p, comment_p) and directives (lexeme_d), however, the parser should be
242 // ch_p match character
243 // eps_p always matches nothing (to attach unconditional actions)
244 // confix_p(a,b,c) match b, preceded by a and terminated by c. Used to parse
245 // string literals and comments
246 // lex_escape_ch_p match a lex style escape char. This is like a C++ style
247 // literal string escape char, however \x will be replaced by 'x'
248 // for any char 'x' if it has no special meaning.
249 // keyword_p match a delimited keyword
250 // comment_p(a,b) match comment starting with a and terminated with b. b
251 // defaults to end-of-line
253 // lexeme_d don't skip whitespace (as defined by the skip parser)
255 // Aligned to the right at column 50 are semantic actions.
257 // For clarity, I have used 'ch_p' explicitly throughout even though it is optional
260 // More info is in the Boost.Spirit documentation
263 = builtin >> statement_end
264 | path >> ( group_start | statement )
266 | ch_p(';') // Ignore empty commands
272 >> eps_p [ self.dispatch(&PD::builtin_cd,
273 boost::ref(self.context.path)) ]
276 >> eps_p [ self.dispatch(&PD::builtin_ls,
277 boost::ref(self.context.path)) ]
278 | keyword_p("exit") [ self.dispatch(&PD::builtin_exit) ]
282 >> eps_p [ self.dispatch(&PD::builtin_help,
283 boost::ref(self.context.path)) ]
287 = ch_p('{') [ self.dispatch(&PD::pushDirectory,
288 boost::ref(self.context.path)) ]
292 = ch_p('}') [ self.dispatch(&PD::popDirectory) ]
296 = eps_p [ self.dispatch(&PD::beginCommand,
297 boost::ref(self.context.path)) ]
299 >> statement_end [ self.dispatch(&PD::endCommand) ]
307 = simple_argument [ self.dispatch(&PD::pushToken,
308 boost::ref(self.context.token)) ]
312 simple_argument // All these return their value in context.token
318 string // Returns value in context.token
319 = eps_p [ clear_a(self.context.str) ]
323 >> * ( ( lex_escape_ch_p[ assign_a(self.context.ch) ]
325 ) [ append_a(self.context.str,
328 >> ch_p('"') [ self.set_token_a(AT::BasicString,
333 hexstring // Returns value in context.token
334 = eps_p [ clear_a(self.context.str) ]
335 >> confix_p( "x\"", * hexbyte, '"' )
336 [ self.set_token_a(AT::HexString,
340 path // Returns value in context.path
341 = eps_p [ clear_a(self.context.path) ]
346 = ( word [ push_back_a(self.context.path,
347 self.context.token) ]
349 >> ( ! ch_p('/') [ push_back_a(self.context.path,
350 self.context.EmptyToken) ] )
354 = ch_p('/') [ push_back_a(self.context.path,
355 self.context.EmptyToken) ]
357 | eps_p [ push_back_a(self.context.path,
358 self.context.EmptyToken) ] )
362 = ch_p('(') [ self.set_token_a(AT::ArgumentGroupOpen) ]
363 [ self.dispatch(&PD::pushToken,
364 boost::ref(self.context.token)) ]
366 >> ch_p(')') [ self.set_token_a(AT::ArgumentGroupClose) ]
367 [ self.dispatch(&PD::pushToken,
368 boost::ref(self.context.token)) ]
372 = simple_argument [ self.dispatch(&PD::pushToken,
373 boost::ref(self.context.token)) ]
374 | punctuation [ self.dispatch(&PD::pushToken,
375 boost::ref(self.context.token)) ]
379 punctuation // Returns value in context.str
380 = ch_p('/') [ self.set_token_a(AT::PathSeparator) ]
381 | ch_p('{') [ self.set_token_a(AT::DirectoryGroupOpen) ]
382 | ch_p('}') [ self.set_token_a(AT::DirectoryGroupClose) ]
383 | ch_p(';') [ self.set_token_a(AT::CommandTerminator) ]
384 | punctuation_p [ self.set_token_a(AT::OtherPunctuation) ]
387 word // Returns value in context.token
390 (+ word_p) [ assign_a(self.context.str) ]
392 >> eps_p [ self.set_token_a(AT::Word, self.context.str) ]
396 = uint_parser<char, 16, 2, 2>()
397 [ append_a(self.context.str) ]
401 = if_p(var(self.incremental)) [
411 = space_p | comment_p('#')
414 ///////////////////////////////////////////////////////////////////
417 command, // CommandParser
419 arguments // ArgumentsParser
422 BOOST_SPIRIT_DEBUG_TRACE_RULE(command,1);
423 BOOST_SPIRIT_DEBUG_TRACE_RULE(path,1);
424 BOOST_SPIRIT_DEBUG_TRACE_RULE(argument,1);
425 BOOST_SPIRIT_DEBUG_TRACE_RULE(word,1);
426 BOOST_SPIRIT_DEBUG_TRACE_RULE(string,1);
427 BOOST_SPIRIT_DEBUG_TRACE_RULE(hexstring,1);
428 BOOST_SPIRIT_DEBUG_TRACE_RULE(token,1);
429 BOOST_SPIRIT_DEBUG_TRACE_RULE(punctuation,1);
430 BOOST_SPIRIT_DEBUG_TRACE_RULE(hexbyte,1);
431 BOOST_SPIRIT_DEBUG_TRACE_RULE(balanced_tokens,1);
432 BOOST_SPIRIT_DEBUG_TRACE_RULE(simple_argument,1);
433 BOOST_SPIRIT_DEBUG_TRACE_RULE(complex_argument,1);
434 BOOST_SPIRIT_DEBUG_TRACE_RULE(builtin,1);
435 BOOST_SPIRIT_DEBUG_TRACE_RULE(commands,1);
436 BOOST_SPIRIT_DEBUG_TRACE_RULE(block,1);
437 BOOST_SPIRIT_DEBUG_TRACE_RULE(statement,1);
438 BOOST_SPIRIT_DEBUG_TRACE_RULE(relpath,1);
439 BOOST_SPIRIT_DEBUG_TRACE_RULE(abspath,1);
444 template <class ParseDispatcher>
445 Token const CommandGrammar<ParseDispatcher>::Context::EmptyToken;
451 ///////////////////////////////ih.e////////////////////////////////////////
458 // comment-column: 40
459 // c-file-style: "senf"
460 // indent-tabs-mode: nil
461 // ispell-local-dictionary: "american"
462 // compile-command: "scons -u test"