4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at
9 // http://senf.berlios.de/license.html
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on,
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
15 // Software distributed under the License is distributed on an "AS IS" basis,
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17 // for the specific language governing rights and limitations under the License.
19 // The Original Code is Fraunhofer FOKUS code.
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V.
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
26 // Stefan Bund <g0dil@berlios.de>
29 \brief Parse internal header */
31 #ifndef IH_SENF_Scheduler_Console_Parse_
32 #define IH_SENF_Scheduler_Console_Parse_ 1
36 #include <senf/config.hh>
38 #if HAVE_BOOST_SPIRIT_INCLUDE_CLASSIC_HPP
39 # include <boost/spirit/include/classic.hpp>
40 # include <boost/spirit/include/classic_grammar_def.hpp>
41 # include <boost/spirit/include/classic_dynamic.hpp>
42 # include <boost/spirit/include/phoenix1.hpp>
44 # include <boost/spirit.hpp>
45 # include <boost/spirit/utility/grammar_def.hpp>
46 # include <boost/spirit/dynamic.hpp>
47 # include <boost/spirit/phoenix.hpp>
50 #include <senf/Utils/Phoenix.hh>
52 //-/////////////////////////////////////////////////////////////////////////////////////////////////
58 #if HAVE_BOOST_SPIRIT_INCLUDE_CLASSIC_HPP
59 namespace boost_spirit = ::boost::spirit::classic;
61 namespace boost_spirit = ::boost::spirit;
66 struct FilePositionWithIndex
67 : public boost_spirit::file_position
71 FilePositionWithIndex(std::string const & file_ = std::string(),
72 int line_ = 1, int column_ = 1, int index_ = 0)
73 : boost_spirit::file_position (file_, line_, column_), index (index_)
76 bool operator==(const FilePositionWithIndex & fp) const
78 return boost_spirit::file_position::operator==(fp) && index == fp.index;
83 template <class A1> struct result { typedef FilePositionWithIndex type; };
84 template <class A1> FilePositionWithIndex operator()(A1 & a1) { return a1.get_position(); }
85 FilePositionWithIndex operator()(char const * a1) { return FilePositionWithIndex(); }
88 ::phoenix::function<PositionOf> const positionOf;
90 //-/////////////////////////////////////////////////////////////////////////////////////////////
93 template <class ParseDispatcher>
94 struct CommandGrammar : boost_spirit::grammar<CommandGrammar<ParseDispatcher> >
96 //-/////////////////////////////////////////////////////////////////////////////////////////
99 enum { CommandParser, SkipParser, ArgumentsParser, PathParser };
101 //-/////////////////////////////////////////////////////////////////////////////////////////
102 // The parse context (variables needed while parsing)
104 typedef Token::TokenType TokenType;
108 std::vector<Token> path;
111 FilePositionWithIndex pos;
116 //-/////////////////////////////////////////////////////////////////////////////////////////
121 //-/////////////////////////////////////////////////////////////////////////////////////////
122 // Dispatching semantic actions
124 ParseDispatcher & dispatcher;
126 //-/////////////////////////////////////////////////////////////////////////////////////////
129 static boost_spirit::chset<> & special_p() {
130 static boost_spirit::chset<> p ("/(){};\"");
133 static boost_spirit::chset<> & punctuation_p() {
134 static boost_spirit::chset<> p (",=");
137 static boost_spirit::chset<> & space_p() {
138 static boost_spirit::chset<> p (" \t\n\r");
141 static boost_spirit::chset<> & invalid_p() {
142 static boost_spirit::chset<> p ((boost_spirit::chset<>('\0') | boost_spirit::chset<>("\x01-\x20")) - space_p() );
145 static boost_spirit::chset<> & word_p() {
146 static boost_spirit::chset<> p (boost_spirit::anychar_p - special_p() - punctuation_p() - space_p() - invalid_p());
149 static boost_spirit::distinct_parser<> & keyword_p() {
150 static boost_spirit::distinct_parser<> p (word_p() | boost_spirit::ch_p('/'));
154 //-/////////////////////////////////////////////////////////////////////////////////////////
158 EndOfStatementExpected,
160 ClosingParenExpected,
164 //-/////////////////////////////////////////////////////////////////////////////////////////
166 CommandGrammar(ParseDispatcher & d, Context & c)
167 : context(c), incremental(false), dispatcher(d) {}
169 template <class Scanner>
171 : public boost_spirit::grammar_def< boost_spirit::rule<Scanner>,
172 boost_spirit::rule<Scanner>,
173 boost_spirit::rule<Scanner>,
174 boost_spirit::rule<Scanner> >
176 boost_spirit::rule<Scanner> command, path, argument, word, string, hexstring,
177 word_or_string, token, punctuation, hexbyte, balanced_tokens, simple_argument,
178 complex_argument, builtin, skip, statement, relpath, abspath, arguments,
179 group_start, group_close, statement_end, opt_path;
181 definition(CommandGrammar const & self)
183 using namespace boost_spirit;
184 using namespace ::phoenix;
185 using namespace senf::phoenix;
186 typedef ParseDispatcher PD;
188 actor< variable< char > > ch_ (self.context.ch);
189 actor< variable< std::string > > str_ (self.context.str);
190 actor< variable< std::vector<Token> > > path_ (self.context.path);
191 actor< variable< Token > > token_ (self.context.token);
192 actor< variable< FilePositionWithIndex > > pos_ (self.context.pos);
193 actor< variable< ParseDispatcher > > d_ (self.dispatcher);
195 assertion<Errors> end_of_statement_expected (EndOfStatementExpected);
196 assertion<Errors> path_expected (PathExpected);
197 assertion<Errors> closing_paren_expected (ClosingParenExpected);
198 assertion<Errors> quote_expected (QuoteExpected);
200 //-/////////////////////////////////////////////////////////////////////////////////
204 // This is EBNF with some minor tweaks to accommodate C++ syntax
206 // * a any number of a's
207 // + a at least one a
209 // a >> b a followed by b
211 // a % b any number of a's separated by b's
214 // Beside this, we use some special parsers (ch_p, eps_p, confix_p, lex_escape_ch_p,
215 // keyword_p, comment_p) and directives (lexeme_d), however, the parser should be
218 // ch_p match character
219 // eps_p always matches nothing (to attach unconditional actions)
220 // confix_p(a,b,c) match b, preceded by a and terminated by c. Used to parse
221 // string literals and comments
222 // lex_escape_ch_p match a lex style escape char. This is like a C++ style
223 // literal string escape char, however \x will be replaced by 'x'
224 // for any char 'x' if it has no special meaning.
225 // keyword_p match a delimited keyword
226 // comment_p(a,b) match comment starting with a and terminated with b. b
227 // defaults to end-of-line
229 // lexeme_d don't skip whitespace (as defined by the skip parser)
231 // Aligned to the right at column 50 are semantic actions.
233 // For clarity, I have used 'ch_p' explicitly throughout even though it is optional
236 // More info is in the Boost.Spirit documentation
239 = builtin >> end_of_statement_expected(statement_end)
241 | ch_p(';') // Ignore empty commands
246 = path_expected(path) [ bind(&PD::beginCommand)(d_, path_) ]
248 >> end_of_statement_expected(
249 ( group_start | statement_end )
250 [ bind(&PD::endCommand)(d_) ]
255 = self.keyword_p()("cd")
256 >> path_expected(path)
257 >> eps_p [ bind(&PD::builtin_cd)(d_, path_) ]
258 | self.keyword_p()("ls")
260 >> eps_p [ bind(&PD::builtin_ls)(d_, path_) ]
261 | self.keyword_p()("ll")
263 >> eps_p [ bind(&PD::builtin_ll)(d_, path_) ]
264 | self.keyword_p()("lr")
266 >> eps_p [ bind(&PD::builtin_lr)(d_, path_) ]
267 | self.keyword_p()("exit") [ bind(&PD::builtin_exit)(d_) ]
268 | self.keyword_p()("help")
270 >> eps_p [ bind(&PD::builtin_help)(d_, path_) ]
274 = ch_p('{') [ bind(&PD::pushDirectory)(d_) ]
278 = ch_p('}') [ bind(&PD::popDirectory)(d_) ]
286 = simple_argument [ bind(&PD::pushToken)(d_, token_) ]
290 simple_argument // All these return their value in context.token
296 string // Returns value in context.token
297 = eps_p [ pos_ = positionOf(arg1) ][ clear(str_) ]
301 >> * ( ( lex_escape_ch_p[ ch_ = arg1 ]
305 >> quote_expected(ch_p('"'))
306 [ token_ = construct_<Token>(Token::BasicString,
312 hexstring // Returns value in context.token
313 = eps_p [ pos_ = positionOf(arg1) ][ clear(str_) ]
315 >> * ( hexbyte - ch_p('"') )
316 >> quote_expected(ch_p('"'))
317 [ token_ = construct_<Token>(Token::HexString,
323 = ! path [ bind(&PD::beginCommand)(d_, path_) ]
324 [ bind(&PD::endCommand)(d_) ]
327 path // Returns value in context.path
328 = eps_p [ clear(path_) ]
333 = ( word_or_string [ push_back(path_, token_) ]
335 >> ( ! (+ch_p('/') ) [ push_back(path_, construct_<Token>()) ] )
339 = (+ch_p('/')) [ push_back(path_, construct_<Token>()) ]
341 | eps_p [ push_back(path_, construct_<Token>()) ] )
345 = eps_p [ pos_ = positionOf(arg1) ]
346 >> ch_p('(') [ token_ = construct_<Token>(
347 Token::ArgumentGroupOpen,
350 [ bind(&PD::pushToken)(d_, token_) ]
352 >> eps_p [ pos_ = positionOf(arg1) ]
353 >> closing_paren_expected(ch_p(')'))
354 [ token_ = construct_<Token>(
355 Token::ArgumentGroupClose,
358 [ bind(&PD::pushToken)(d_, token_) ]
362 = simple_argument [ bind(&PD::pushToken)(d_, token_) ]
363 | punctuation [ bind(&PD::pushToken)(d_, token_) ]
367 punctuation // Returns value in context.str
368 = eps_p [ pos_ = positionOf(arg1) ]
370 ch_p('/') [ token_ = construct_<Token>(
371 Token::PathSeparator,
373 | ch_p('{') [ token_ = construct_<Token>(
374 Token::DirectoryGroupOpen,
376 | ch_p('}') [ token_ = construct_<Token>(
377 Token::DirectoryGroupClose,
379 | ch_p(';') [ token_ = construct_<Token>(
380 Token::CommandTerminator,
382 | self.punctuation_p() [ token_ = construct_<Token>(
383 Token::OtherPunctuation,
384 construct_<std::string>(1u, arg1),
389 word // Returns value in context.token
390 = eps_p [ pos_ = positionOf(arg1) ]
393 (+ self.word_p()) [ str_ = construct_<std::string>(arg1, arg2) ]
395 >> eps_p [ token_ = construct_<Token>(
407 = uint_parser<char, 16, 2, 2>()
408 [ push_back(str_, arg1) ]
412 = if_p(var(self.incremental)) [
422 = self.space_p() | comment_p('#')
425 //-/////////////////////////////////////////////////////////////////////////////////
428 command, // CommandParser
430 arguments, // ArgumentsParser
431 opt_path // PathParser
434 BOOST_SPIRIT_DEBUG_TRACE_RULE(command,1);
435 BOOST_SPIRIT_DEBUG_TRACE_RULE(path,1);
436 BOOST_SPIRIT_DEBUG_TRACE_RULE(argument,1);
437 BOOST_SPIRIT_DEBUG_TRACE_RULE(word,1);
438 BOOST_SPIRIT_DEBUG_TRACE_RULE(string,1);
439 BOOST_SPIRIT_DEBUG_TRACE_RULE(hexstring,1);
440 BOOST_SPIRIT_DEBUG_TRACE_RULE(token,1);
441 BOOST_SPIRIT_DEBUG_TRACE_RULE(punctuation,1);
442 BOOST_SPIRIT_DEBUG_TRACE_RULE(hexbyte,1);
443 BOOST_SPIRIT_DEBUG_TRACE_RULE(balanced_tokens,1);
444 BOOST_SPIRIT_DEBUG_TRACE_RULE(simple_argument,1);
445 BOOST_SPIRIT_DEBUG_TRACE_RULE(complex_argument,1);
446 BOOST_SPIRIT_DEBUG_TRACE_RULE(builtin,1);
447 BOOST_SPIRIT_DEBUG_TRACE_RULE(commands,1);
448 BOOST_SPIRIT_DEBUG_TRACE_RULE(block,1);
449 BOOST_SPIRIT_DEBUG_TRACE_RULE(statement,1);
450 BOOST_SPIRIT_DEBUG_TRACE_RULE(relpath,1);
451 BOOST_SPIRIT_DEBUG_TRACE_RULE(abspath,1);
460 //-/////////////////////////////////////////////////////////////////////////////////////////////////
467 // comment-column: 40
468 // c-file-style: "senf"
469 // indent-tabs-mode: nil
470 // ispell-local-dictionary: "american"
471 // compile-command: "scons -u test"