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/bind.hpp>
36 #include <boost/function.hpp>
37 #include <boost/ref.hpp>
39 ///////////////////////////////ih.p////////////////////////////////////////
49 template <class T, class Value>
50 void act(T & ref, Value const & value) const
51 { ref += T(1, value); }
53 template <class T, class Iterator>
54 void act(T & ref, Iterator const & f, Iterator const & l) const
59 inline boost::spirit::ref_value_actor<T, append_action>
62 return boost::spirit::ref_value_actor<T, append_action>(ref);
65 template <class T, class Value>
66 inline boost::spirit::ref_const_ref_actor<T, Value, append_action>
67 append_a(T & ref, Value const & value)
69 return boost::spirit::ref_const_ref_actor<T, Value, append_action>(ref, value);
72 template <class ParseDispatcher>
73 struct CommandGrammar : boost::spirit::grammar<CommandGrammar<ParseDispatcher> >
75 ///////////////////////////////////////////////////////////////////////////
78 enum { CommandParser, SkipParser };
80 ///////////////////////////////////////////////////////////////////////////
81 // The parse context (variables needed while parsing)
85 std::vector<std::string> path;
91 ///////////////////////////////////////////////////////////////////////////
92 // Dispatching semantic actions
94 ParseDispatcher & dispatcher;
98 Dispatch_actor(boost::function<void ()> fn_) : fn (fn_) {}
100 template <class Value>
101 void operator()(Value const & value) const
104 template <class Iterator>
105 void operator()(Iterator const & f, Iterator const & l) const
108 boost::function<void ()> fn;
111 template <class Callback>
112 Dispatch_actor dispatch(Callback cb) const
113 { return Dispatch_actor(boost::bind(cb, boost::ref(dispatcher))); }
115 template <class Callback, class Arg>
116 Dispatch_actor dispatch(Callback cb, Arg const & arg) const
117 { return Dispatch_actor(boost::bind(cb, boost::ref(dispatcher), arg)); }
119 ///////////////////////////////////////////////////////////////////////////
121 CommandGrammar(ParseDispatcher & d, Context & c)
122 : context(c), dispatcher(d) {}
124 template <class Scanner>
126 : public boost::spirit::grammar_def< boost::spirit::rule<Scanner>,
127 boost::spirit::rule<Scanner> >
129 boost::spirit::rule<Scanner> command, path, argument, word, string, hexstring, token,
130 punctuation, hexbyte, balanced_tokens, simple_argument, complex_argument, builtin,
131 skip, commands, block, statement, relpath, abspath;
132 boost::spirit::chset<> special_p, punctuation_p, space_p, invalid_p, word_p;
133 boost::spirit::distinct_parser<> keyword_p;
135 definition(CommandGrammar const & self) :
137 // Characters with a special meaning within the parser
138 special_p ("/(){};"),
140 // Characters which are returned as punctuation tokens
141 punctuation_p (",="),
143 // Whitespace characters
146 // Invalid characters: All chars below \x20 (space) which are not space_p
147 // (don't put a \0 in the chset<> argument *string* ...)
149 boost::spirit::chset<>('\0') | boost::spirit::chset<>("\x01-\x20") - space_p ),
151 // Valid word characters
153 boost::spirit::anychar_p - special_p - punctuation_p - space_p - invalid_p),
155 // Keywords must not be followed by a word char or '/'
156 keyword_p ( word_p | boost::spirit::ch_p('/') )
159 using namespace boost::spirit;
160 typedef ParseDispatcher PD;
162 ///////////////////////////////////////////////////////////////////
166 // This is EBNF with some minor tweaks to accommodate C++ syntax
168 // * and + precede their argument
171 // a % b match any number of a's separated by b
172 // a - b match a but not b
174 // Beside this, we use some special parsers (ch_p, eps_p, confix_p, lex_escape_ch_p,
175 // keyword_p, comment_p) and directives (lexeme_d), however, the parser should be
178 // ch_p match character
179 // eps_p always matches nothing (to attach unconditional actions)
180 // confix_p(a,b,c) match b, preceded by a and terminated by c. Used to parse
181 // string literals and comments
182 // lex_escape_ch_p match a lex style escape char. This is like a C++ style
183 // literal string escape char, however \x will be replaced by 'x'
184 // for any char 'x' if it has no special meaning.
185 // keyword_p match a delimited keyword
186 // comment_p(a,b) match comment starting with a and terminated with b. b
187 // defaults to end-of-line
189 // lexeme_d don't skip whitespace (as defined by the skip parser)
191 // Aligned to the right at column 50 are semantic actions.
193 // For clarity, I have used 'ch_p' explicitly throughout even though it is auxiliary
196 // More info is in the Boost.Spirit documentation
203 = builtin >> (ch_p(';') | end_p)
204 | path >> ( block | statement )
205 | ch_p(';') // Ignore empty commands
211 >> eps_p [ self.dispatch(&PD::builtin_cd,
212 boost::ref(self.context.path)) ]
215 >> eps_p [ self.dispatch(&PD::builtin_ls,
216 boost::ref(self.context.path)) ]
217 | keyword_p("exit") [ self.dispatch(&PD::builtin_exit) ]
221 >> eps_p [ self.dispatch(&PD::builtin_help,
222 boost::ref(self.context.path)) ]
226 = ch_p('{') [ self.dispatch(&PD::pushDirectory,
227 boost::ref(self.context.path)) ]
229 >> ch_p('}') [ self.dispatch(&PD::popDirectory) ]
233 = eps_p [ self.dispatch(&PD::beginCommand,
234 boost::ref(self.context.path)) ]
236 >> (ch_p(';') | end_p)
237 >> eps_p [ self.dispatch(&PD::endCommand) ]
241 = simple_argument [ self.dispatch(&PD::pushArgument,
242 boost::ref(self.context.str)) ]
246 simple_argument // All these return their value in context.str
252 complex_argument // Argument consists of multiple tokens
253 = ch_p('(') [ self.dispatch(&PD::openGroup) ]
255 >> ch_p(')') [ self.dispatch(&PD::closeGroup) ]
258 string // Returns value in context.str
259 = eps_p [ clear_a(self.context.str) ]
263 >> * ( ( lex_escape_ch_p[ assign_a(self.context.ch) ]
265 ) [ append_a(self.context.str,
272 hexstring // Returns value in context.str
273 = eps_p [ clear_a(self.context.str) ]
274 >> confix_p( "x\"", * hexbyte, '"' )
277 path // Returns value in context.path
278 = eps_p [ clear_a(self.context.path) ]
283 = ( word [ push_back_a(self.context.path) ]
285 >> ( ! ch_p('/') [ push_back_a(self.context.path,"") ] )
289 = ch_p('/') [ push_back_a(self.context.path, "") ]
291 | eps_p [ push_back_a(self.context.path, "") ] )
295 = ch_p('(') [ self.dispatch(&PD::pushPunctuation, "(") ]
297 >> ch_p(')') [ self.dispatch(&PD::pushPunctuation, ")") ]
301 = simple_argument [ self.dispatch(&PD::pushWord,
302 boost::ref(self.context.str)) ]
303 | punctuation [ self.dispatch(&PD::pushPunctuation,
304 boost::ref(self.context.str)) ]
308 punctuation // Returns value in context.str
309 = punctuation_p [ assign_a(self.context.str) ]
312 word // Returns value in context.str
313 = lexeme_d[ + word_p ] [ assign_a(self.context.str) ]
317 = uint_parser<char, 16, 2, 2>()
318 [ append_a(self.context.str) ]
322 = space_p | comment_p('#')
325 ///////////////////////////////////////////////////////////////////
328 commands, // CommandParser
332 BOOST_SPIRIT_DEBUG_TRACE_RULE(command,1);
333 BOOST_SPIRIT_DEBUG_TRACE_RULE(path,1);
334 BOOST_SPIRIT_DEBUG_TRACE_RULE(argument,1);
335 BOOST_SPIRIT_DEBUG_TRACE_RULE(word,1);
336 BOOST_SPIRIT_DEBUG_TRACE_RULE(string,1);
337 BOOST_SPIRIT_DEBUG_TRACE_RULE(hexstring,1);
338 BOOST_SPIRIT_DEBUG_TRACE_RULE(token,1);
339 BOOST_SPIRIT_DEBUG_TRACE_RULE(punctuation,1);
340 BOOST_SPIRIT_DEBUG_TRACE_RULE(hexbyte,1);
341 BOOST_SPIRIT_DEBUG_TRACE_RULE(balanced_tokens,1);
342 BOOST_SPIRIT_DEBUG_TRACE_RULE(simple_argument,1);
343 BOOST_SPIRIT_DEBUG_TRACE_RULE(complex_argument,1);
344 BOOST_SPIRIT_DEBUG_TRACE_RULE(builtin,1);
345 BOOST_SPIRIT_DEBUG_TRACE_RULE(commands,1);
346 BOOST_SPIRIT_DEBUG_TRACE_RULE(block,1);
347 BOOST_SPIRIT_DEBUG_TRACE_RULE(statement,1);
348 BOOST_SPIRIT_DEBUG_TRACE_RULE(relpath,1);
349 BOOST_SPIRIT_DEBUG_TRACE_RULE(abspath,1);
358 ///////////////////////////////ih.e////////////////////////////////////////
365 // comment-column: 40
366 // c-file-style: "senf"
367 // indent-tabs-mode: nil
368 // ispell-local-dictionary: "american"
369 // compile-command: "scons -u test"