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 */
26 #ifndef IH_SENF_Scheduler_Console_Parse_
27 #define IH_SENF_Scheduler_Console_Parse_ 1
31 #include "../../config.hh"
32 #include <boost/spirit.hpp>
33 #include <boost/spirit/utility/grammar_def.hpp>
34 #include <boost/spirit/dynamic.hpp>
35 #include <boost/spirit/phoenix.hpp>
36 #include "../../Utils/Phoenix.hh"
38 ///////////////////////////////ih.p////////////////////////////////////////
46 struct FilePositionWithIndex
47 : public boost::spirit::file_position
51 FilePositionWithIndex(std::string const & file_ = std::string(),
52 int line_ = 1, int column_ = 1, int index_ = 0)
53 : boost::spirit::file_position (file_, line_, column_), index (index_)
56 bool operator==(const FilePositionWithIndex & fp) const
58 return boost::spirit::file_position::operator==(fp) && index == fp.index;
63 template <class A1> struct result { typedef FilePositionWithIndex type; };
64 template <class A1> FilePositionWithIndex operator()(A1 & a1) { return a1.get_position(); }
65 FilePositionWithIndex operator()(char const * a1) { return FilePositionWithIndex(); }
68 ::phoenix::function<PositionOf> const positionOf;
70 ///////////////////////////////////////////////////////////////////////////
73 template <class ParseDispatcher>
74 struct CommandGrammar : boost::spirit::grammar<CommandGrammar<ParseDispatcher> >
76 ///////////////////////////////////////////////////////////////////////////
79 enum { CommandParser, SkipParser, ArgumentsParser, PathParser };
81 ///////////////////////////////////////////////////////////////////////////
82 // The parse context (variables needed while parsing)
84 typedef Token::TokenType TokenType;
88 std::vector<Token> path;
91 FilePositionWithIndex pos;
96 ///////////////////////////////////////////////////////////////////////////
101 ///////////////////////////////////////////////////////////////////////////
102 // Dispatching semantic actions
104 ParseDispatcher & dispatcher;
106 //////////////////////////////////////////////////////////////////////////
109 static boost::spirit::chset<> special_p;
110 static boost::spirit::chset<> punctuation_p;
111 static boost::spirit::chset<> space_p;
112 static boost::spirit::chset<> invalid_p;
113 static boost::spirit::chset<> word_p;
114 static boost::spirit::distinct_parser<> keyword_p;
116 ///////////////////////////////////////////////////////////////////////////
120 EndOfStatementExpected,
122 ClosingParenExpected,
126 ///////////////////////////////////////////////////////////////////////////
128 CommandGrammar(ParseDispatcher & d, Context & c)
129 : context(c), incremental(false), dispatcher(d) {}
131 template <class Scanner>
133 : public boost::spirit::grammar_def< boost::spirit::rule<Scanner>,
134 boost::spirit::rule<Scanner>,
135 boost::spirit::rule<Scanner>,
136 boost::spirit::rule<Scanner> >
138 boost::spirit::rule<Scanner> command, path, argument, word, string, hexstring, token,
139 punctuation, hexbyte, balanced_tokens, simple_argument, complex_argument, builtin,
140 skip, statement, relpath, abspath, arguments, group_start, group_close,
141 statement_end, opt_path;
143 definition(CommandGrammar const & self)
145 using namespace boost::spirit;
146 using namespace ::phoenix;
147 using namespace senf::phoenix;
148 typedef ParseDispatcher PD;
150 actor< variable< char > > ch_ (self.context.ch);
151 actor< variable< std::string > > str_ (self.context.str);
152 actor< variable< std::vector<Token> > > path_ (self.context.path);
153 actor< variable< Token > > token_ (self.context.token);
154 actor< variable< FilePositionWithIndex > > pos_ (self.context.pos);
155 actor< variable< ParseDispatcher > > d_ (self.dispatcher);
157 assertion<Errors> end_of_statement_expected (EndOfStatementExpected);
158 assertion<Errors> path_expected (PathExpected);
159 assertion<Errors> closing_paren_expected (ClosingParenExpected);
160 assertion<Errors> quote_expected (QuoteExpected);
162 ///////////////////////////////////////////////////////////////////
166 // This is EBNF with some minor tweaks to accommodate C++ syntax
168 // * a any number of a's
169 // + a at least one a
171 // a >> b a followed by b
173 // a % b any number of a's separated by b's
176 // Beside this, we use some special parsers (ch_p, eps_p, confix_p, lex_escape_ch_p,
177 // keyword_p, comment_p) and directives (lexeme_d), however, the parser should be
180 // ch_p match character
181 // eps_p always matches nothing (to attach unconditional actions)
182 // confix_p(a,b,c) match b, preceded by a and terminated by c. Used to parse
183 // string literals and comments
184 // lex_escape_ch_p match a lex style escape char. This is like a C++ style
185 // literal string escape char, however \x will be replaced by 'x'
186 // for any char 'x' if it has no special meaning.
187 // keyword_p match a delimited keyword
188 // comment_p(a,b) match comment starting with a and terminated with b. b
189 // defaults to end-of-line
191 // lexeme_d don't skip whitespace (as defined by the skip parser)
193 // Aligned to the right at column 50 are semantic actions.
195 // For clarity, I have used 'ch_p' explicitly throughout even though it is optional
198 // More info is in the Boost.Spirit documentation
201 = builtin >> end_of_statement_expected(statement_end)
203 | ch_p(';') // Ignore empty commands
208 = path_expected(path) [ bind(&PD::beginCommand)(d_, path_) ]
210 >> end_of_statement_expected(
211 ( group_start | statement_end )
212 [ bind(&PD::endCommand)(d_) ]
217 = self.keyword_p("cd")
218 >> path_expected(path)
219 >> eps_p [ bind(&PD::builtin_cd)(d_, path_) ]
220 | self.keyword_p("ls")
222 >> eps_p [ bind(&PD::builtin_ls)(d_, path_) ]
223 | self.keyword_p("lr")
225 >> eps_p [ bind(&PD::builtin_lr)(d_, path_) ]
226 | self.keyword_p("exit") [ bind(&PD::builtin_exit)(d_) ]
227 | self.keyword_p("help")
229 >> eps_p [ bind(&PD::builtin_help)(d_, path_) ]
233 = ch_p('{') [ bind(&PD::pushDirectory)(d_) ]
237 = ch_p('}') [ bind(&PD::popDirectory)(d_) ]
245 = simple_argument [ bind(&PD::pushToken)(d_, token_) ]
249 simple_argument // All these return their value in context.token
255 string // Returns value in context.token
256 = eps_p [ pos_ = positionOf(arg1) ][ clear(str_) ]
260 >> * ( ( lex_escape_ch_p[ ch_ = arg1 ]
264 >> quote_expected(ch_p('"'))
265 [ token_ = construct_<Token>(Token::BasicString,
271 hexstring // Returns value in context.token
272 = eps_p [ pos_ = positionOf(arg1) ][ clear(str_) ]
274 >> * ( hexbyte - ch_p('"') )
275 >> quote_expected(ch_p('"'))
276 [ token_ = construct_<Token>(Token::HexString,
282 = ! path [ bind(&PD::beginCommand)(d_, path_) ]
283 [ bind(&PD::endCommand)(d_) ]
286 path // Returns value in context.path
287 = eps_p [ clear(path_) ]
292 = ( word [ push_back(path_, token_) ]
294 >> ( ! ch_p('/') [ push_back(path_, construct_<Token>()) ] )
298 = ch_p('/') [ push_back(path_, construct_<Token>()) ]
300 | eps_p [ push_back(path_, construct_<Token>()) ] )
304 = eps_p [ pos_ = positionOf(arg1) ]
305 >> ch_p('(') [ token_ = construct_<Token>(
306 Token::ArgumentGroupOpen,
309 [ bind(&PD::pushToken)(d_, token_) ]
311 >> eps_p [ pos_ = positionOf(arg1) ]
312 >> closing_paren_expected(ch_p(')'))
313 [ token_ = construct_<Token>(
314 Token::ArgumentGroupClose,
317 [ bind(&PD::pushToken)(d_, token_) ]
321 = simple_argument [ bind(&PD::pushToken)(d_, token_) ]
322 | punctuation [ bind(&PD::pushToken)(d_, token_) ]
326 punctuation // Returns value in context.str
327 = eps_p [ pos_ = positionOf(arg1) ]
329 ch_p('/') [ token_ = construct_<Token>(
330 Token::PathSeparator,
332 | ch_p('{') [ token_ = construct_<Token>(
333 Token::DirectoryGroupOpen,
335 | ch_p('}') [ token_ = construct_<Token>(
336 Token::DirectoryGroupClose,
338 | ch_p(';') [ token_ = construct_<Token>(
339 Token::CommandTerminator,
341 | self.punctuation_p [ token_ = construct_<Token>(
342 Token::OtherPunctuation,
343 construct_<std::string>(1u, arg1),
348 word // Returns value in context.token
349 = eps_p [ pos_ = positionOf(arg1) ]
352 (+ self.word_p) [ str_ = construct_<std::string>(arg1, arg2) ]
354 >> eps_p [ token_ = construct_<Token>(
361 = uint_parser<char, 16, 2, 2>()
362 [ push_back(str_, arg1) ]
366 = if_p(var(self.incremental)) [
376 = self.space_p | comment_p('#')
379 ///////////////////////////////////////////////////////////////////
382 command, // CommandParser
384 arguments, // ArgumentsParser
385 opt_path // PathParser
388 BOOST_SPIRIT_DEBUG_TRACE_RULE(command,1);
389 BOOST_SPIRIT_DEBUG_TRACE_RULE(path,1);
390 BOOST_SPIRIT_DEBUG_TRACE_RULE(argument,1);
391 BOOST_SPIRIT_DEBUG_TRACE_RULE(word,1);
392 BOOST_SPIRIT_DEBUG_TRACE_RULE(string,1);
393 BOOST_SPIRIT_DEBUG_TRACE_RULE(hexstring,1);
394 BOOST_SPIRIT_DEBUG_TRACE_RULE(token,1);
395 BOOST_SPIRIT_DEBUG_TRACE_RULE(punctuation,1);
396 BOOST_SPIRIT_DEBUG_TRACE_RULE(hexbyte,1);
397 BOOST_SPIRIT_DEBUG_TRACE_RULE(balanced_tokens,1);
398 BOOST_SPIRIT_DEBUG_TRACE_RULE(simple_argument,1);
399 BOOST_SPIRIT_DEBUG_TRACE_RULE(complex_argument,1);
400 BOOST_SPIRIT_DEBUG_TRACE_RULE(builtin,1);
401 BOOST_SPIRIT_DEBUG_TRACE_RULE(commands,1);
402 BOOST_SPIRIT_DEBUG_TRACE_RULE(block,1);
403 BOOST_SPIRIT_DEBUG_TRACE_RULE(statement,1);
404 BOOST_SPIRIT_DEBUG_TRACE_RULE(relpath,1);
405 BOOST_SPIRIT_DEBUG_TRACE_RULE(abspath,1);
410 template <class PD> boost::spirit::chset<> CommandGrammar<PD>::special_p (
412 template <class PD> boost::spirit::chset<> CommandGrammar<PD>::punctuation_p (
414 template <class PD> boost::spirit::chset<> CommandGrammar<PD>::space_p (
416 template <class PD> boost::spirit::chset<> CommandGrammar<PD>::invalid_p (
417 (boost::spirit::chset<>('\0') | boost::spirit::chset<>("\x01-\x20")) - space_p );
418 template <class PD> boost::spirit::chset<> CommandGrammar<PD>::word_p (
419 boost::spirit::anychar_p - special_p - punctuation_p - space_p - invalid_p);
420 template <class PD> boost::spirit::distinct_parser<> CommandGrammar<PD>::keyword_p (
421 word_p | boost::spirit::ch_p('/'));
427 ///////////////////////////////ih.e////////////////////////////////////////
434 // comment-column: 40
435 // c-file-style: "senf"
436 // indent-tabs-mode: nil
437 // ispell-local-dictionary: "american"
438 // compile-command: "scons -u test"