Search:

SENF Extensible Network Framework

  • Home
  • Download
  • Wiki
  • BerliOS
  • ChangeLog
  • Browse SVN
  • Bug Tracker
  • Overview
  • Examples
  • HowTos
  • Glossary
  • PPI
  • Packets
  • Scheduler
  • Socket
  • Utils
  • Console
  • Daemon
  • Logger
  • Termlib
  • Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

Parse.ih

Go to the documentation of this file.
00001 // $Id: Parse.ih 1742 2010-11-04 14:51:56Z g0dil $
00002 //
00003 // Copyright (C) 2008
00004 // Fraunhofer (FOKUS)
00005 // Competence Center NETwork research (NET), St. Augustin, GERMANY
00006 //     Stefan Bund <g0dil@berlios.de>
00007 //
00008 // This program is free software; you can redistribute it and/or modify
00009 // it under the terms of the GNU General Public License as published by
00010 // the Free Software Foundation; either version 2 of the License, or
00011 // (at your option) any later version.
00012 //
00013 // This program is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 // GNU General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU General Public License
00019 // along with this program; if not, write to the
00020 // Free Software Foundation, Inc.,
00021 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022 
00026 #ifndef IH_SENF_Scheduler_Console_Parse_
00027 #define IH_SENF_Scheduler_Console_Parse_ 1
00028 
00029 // Custom includes
00030 #include <vector>
00031 #include <senf/config.hh>
00032 
00033 #if HAVE_BOOST_SPIRIT_INCLUDE_CLASSIC_HPP
00034 #  include <boost/spirit/include/classic.hpp>
00035 #  include <boost/spirit/include/classic_grammar_def.hpp>
00036 #  include <boost/spirit/include/classic_dynamic.hpp>
00037 #  include <boost/spirit/include/phoenix1.hpp>
00038 #else
00039 #  include <boost/spirit.hpp>
00040 #  include <boost/spirit/utility/grammar_def.hpp>
00041 #  include <boost/spirit/dynamic.hpp>
00042 #  include <boost/spirit/phoenix.hpp>
00043 #endif
00044 
00045 #include <senf/Utils/Phoenix.hh>
00046 
00047 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00048 
00049 namespace senf {
00050 namespace console {
00051 namespace detail {
00052 
00053 #if HAVE_BOOST_SPIRIT_INCLUDE_CLASSIC_HPP
00054     namespace boost_spirit = ::boost::spirit::classic;
00055 #else
00056     namespace boost_spirit = ::boost::spirit;
00057 #endif
00058 
00059 #ifndef DOXYGEN
00060 
00061     struct FilePositionWithIndex
00062         : public boost_spirit::file_position
00063     {
00064         int index;
00065 
00066         FilePositionWithIndex(std::string const & file_ = std::string(),
00067                                  int line_ = 1, int column_ = 1, int index_ = 0)
00068             : boost_spirit::file_position (file_, line_, column_), index (index_)
00069             {}
00070 
00071         bool operator==(const FilePositionWithIndex & fp) const
00072             {
00073                 return boost_spirit::file_position::operator==(fp) && index == fp.index;
00074             }
00075     };
00076 
00077     struct PositionOf {
00078         template <class A1> struct result { typedef FilePositionWithIndex type; };
00079         template <class A1> FilePositionWithIndex operator()(A1 & a1) { return a1.get_position(); }
00080         FilePositionWithIndex operator()(char const * a1) { return FilePositionWithIndex(); }
00081     };
00082 
00083     ::phoenix::function<PositionOf> const positionOf;
00084 
00085     //-/////////////////////////////////////////////////////////////////////////////////////////////
00086     // Grammar
00087 
00088     template <class ParseDispatcher>
00089     struct CommandGrammar : boost_spirit::grammar<CommandGrammar<ParseDispatcher> >
00090     {
00091         //-/////////////////////////////////////////////////////////////////////////////////////////
00092         // Start rules
00093 
00094         enum { CommandParser, SkipParser, ArgumentsParser, PathParser };
00095 
00096         //-/////////////////////////////////////////////////////////////////////////////////////////
00097         // The parse context (variables needed while parsing)
00098 
00099         typedef Token::TokenType TokenType;
00100 
00101         struct Context {
00102             std::string str;
00103             std::vector<Token> path;
00104             char ch;
00105             Token token;
00106             FilePositionWithIndex pos;
00107         };
00108 
00109         Context & context;
00110 
00111         //-/////////////////////////////////////////////////////////////////////////////////////////
00112         // Configuration
00113 
00114         bool incremental;
00115 
00116         //-/////////////////////////////////////////////////////////////////////////////////////////
00117         // Dispatching semantic actions
00118 
00119         ParseDispatcher & dispatcher;
00120 
00121         //-/////////////////////////////////////////////////////////////////////////////////////////
00122         // charachter sets
00123 
00124         static boost_spirit::chset<> special_p;
00125         static boost_spirit::chset<> punctuation_p;
00126         static boost_spirit::chset<> space_p;
00127         static boost_spirit::chset<> invalid_p;
00128         static boost_spirit::chset<> word_p;
00129         static boost_spirit::distinct_parser<> keyword_p;
00130 
00131         //-/////////////////////////////////////////////////////////////////////////////////////////
00132         // Errors
00133 
00134         enum Errors {
00135             EndOfStatementExpected,
00136             PathExpected,
00137             ClosingParenExpected,
00138             QuoteExpected
00139         };
00140 
00141         //-/////////////////////////////////////////////////////////////////////////////////////////
00142 
00143         CommandGrammar(ParseDispatcher & d, Context & c)
00144             : context(c), incremental(false), dispatcher(d) {}
00145 
00146         template <class Scanner>
00147         struct definition
00148             : public boost_spirit::grammar_def< boost_spirit::rule<Scanner>,
00149                                                  boost_spirit::rule<Scanner>,
00150                                                  boost_spirit::rule<Scanner>,
00151                                                  boost_spirit::rule<Scanner> >
00152         {
00153             boost_spirit::rule<Scanner> command, path, argument, word, string, hexstring,
00154                 word_or_string, token, punctuation, hexbyte, balanced_tokens, simple_argument,
00155                 complex_argument, builtin, skip, statement, relpath, abspath, arguments,
00156                 group_start, group_close, statement_end, opt_path;
00157 
00158             definition(CommandGrammar const & self)
00159             {
00160                 using namespace boost_spirit;
00161                 using namespace ::phoenix;
00162                 using namespace senf::phoenix;
00163                 typedef ParseDispatcher PD;
00164 
00165                 actor< variable< char > >                  ch_    (self.context.ch);
00166                 actor< variable< std::string > >           str_   (self.context.str);
00167                 actor< variable< std::vector<Token> > >    path_  (self.context.path);
00168                 actor< variable< Token > >                 token_ (self.context.token);
00169                 actor< variable< FilePositionWithIndex > > pos_   (self.context.pos);
00170                 actor< variable< ParseDispatcher > >       d_     (self.dispatcher);
00171 
00172                 assertion<Errors> end_of_statement_expected   (EndOfStatementExpected);
00173                 assertion<Errors> path_expected               (PathExpected);
00174                 assertion<Errors> closing_paren_expected      (ClosingParenExpected);
00175                 assertion<Errors> quote_expected              (QuoteExpected);
00176 
00177                 //-/////////////////////////////////////////////////////////////////////////////////
00178                 // Spirit grammar
00179                 //
00180                 // Syntax summary:
00181                 // This is EBNF with some minor tweaks to accommodate C++ syntax
00182                 //
00183                 //   * a        any number of a's
00184                 //   + a        at least one a
00185                 //   ! a        an optional a
00186                 //   a >> b     a followed by b
00187                 //   a | b      a or b
00188                 //   a % b      any number of a's separated by b's
00189                 //   a - b      a but not b
00190                 //
00191                 // Beside this, we use some special parsers (ch_p, eps_p, confix_p, lex_escape_ch_p,
00192                 // keyword_p, comment_p) and directives (lexeme_d), however, the parser should be
00193                 // quite readable.
00194                 //
00195                 //   ch_p             match character
00196                 //   eps_p            always matches nothing (to attach unconditional actions)
00197                 //   confix_p(a,b,c)  match b, preceded by a and terminated by c. Used to parse
00198                 //                    string literals and comments
00199                 //   lex_escape_ch_p  match a lex style escape char. This is like a C++ style
00200                 //                    literal string escape char, however \x will be replaced by 'x'
00201                 //                    for any char 'x' if it has no special meaning.
00202                 //   keyword_p        match a delimited keyword
00203                 //   comment_p(a,b)   match comment starting with a and terminated with b. b
00204                 //                    defaults to end-of-line
00205                 //
00206                 //   lexeme_d         don't skip whitespace (as defined by the skip parser)
00207                 //
00208                 // Aligned to the right at column 50 are semantic actions.
00209                 //
00210                 // For clarity, I have used 'ch_p' explicitly throughout even though it is optional
00211                 // in most cases.
00212                 //
00213                 // More info is in the Boost.Spirit documentation
00214 
00215                 command
00216                     =    builtin >> end_of_statement_expected(statement_end)
00217                     |    group_close
00218                     |    ch_p(';') // Ignore empty commands
00219                     |    statement
00220                     ;
00221 
00222                 statement
00223                     =    path_expected(path)      [ bind(&PD::beginCommand)(d_, path_) ]
00224                       >> arguments
00225                       >> end_of_statement_expected(
00226                            ( group_start | statement_end )
00227                                                   [ bind(&PD::endCommand)(d_) ]
00228                          )
00229                     ;
00230 
00231                 builtin
00232                     =    self.keyword_p("cd")
00233                       >> path_expected(path)
00234                       >> eps_p                    [ bind(&PD::builtin_cd)(d_, path_) ]
00235                     |    self.keyword_p("ls")
00236                       >> ! path
00237                       >> eps_p                    [ bind(&PD::builtin_ls)(d_, path_) ]
00238                     |    self.keyword_p("ll")
00239                       >> ! path
00240                       >> eps_p                    [ bind(&PD::builtin_ll)(d_, path_) ]
00241                     |    self.keyword_p("lr")
00242                       >> ! path
00243                       >> eps_p                    [ bind(&PD::builtin_lr)(d_, path_) ]
00244                     |    self.keyword_p("exit")   [ bind(&PD::builtin_exit)(d_) ]
00245                     |    self.keyword_p("help")
00246                       >> ! path
00247                       >> eps_p                    [ bind(&PD::builtin_help)(d_, path_) ]
00248                     ;
00249 
00250                 group_start
00251                     =    ch_p('{')                [ bind(&PD::pushDirectory)(d_) ]
00252                     ;
00253 
00254                 group_close
00255                     =    ch_p('}')                [ bind(&PD::popDirectory)(d_) ]
00256                     ;
00257 
00258                 arguments
00259                     =    * argument
00260                     ;
00261 
00262                 argument
00263                     =    simple_argument          [ bind(&PD::pushToken)(d_, token_) ]
00264                     |    balanced_tokens
00265                     ;
00266 
00267                 simple_argument         // All these return their value in context.token
00268                     =    string
00269                     |    hexstring
00270                     |    word
00271                     ;
00272 
00273                 string                  // Returns value in context.token
00274                     =    eps_p                    [ pos_ = positionOf(arg1) ][ clear(str_) ]
00275                       >> lexeme_d
00276                          [
00277                              ch_p('"')
00278                           >> * ( ( lex_escape_ch_p[ ch_ = arg1 ]
00279                                    - '"'
00280                                  )                [ str_ += ch_ ]
00281                                )
00282                           >> quote_expected(ch_p('"'))
00283                                                   [ token_ = construct_<Token>(Token::BasicString,
00284                                                                                str_,
00285                                                                                pos_) ]
00286                          ]
00287                     ;
00288 
00289                 hexstring               // Returns value in context.token
00290                     =    eps_p                    [ pos_ = positionOf(arg1) ][ clear(str_) ]
00291                       >>  "x\""
00292                       >> * ( hexbyte - ch_p('"') )
00293                       >> quote_expected(ch_p('"'))
00294                                                   [ token_ = construct_<Token>(Token::HexString,
00295                                                                                str_,
00296                                                                                pos_) ]
00297                     ;
00298 
00299                 opt_path
00300                     = ! path                      [ bind(&PD::beginCommand)(d_, path_) ]
00301                                                   [ bind(&PD::endCommand)(d_) ]
00302                     ;
00303 
00304                 path                    // Returns value in context.path
00305                     =    eps_p                    [ clear(path_) ]
00306                       >> relpath | abspath
00307                     ;
00308 
00309                 relpath
00310                     =    (   word_or_string       [ push_back(path_, token_) ]
00311                            % +ch_p('/') )
00312                       >> ( ! (+ch_p('/') )        [ push_back(path_, construct_<Token>()) ] )
00313                     ;
00314 
00315                 abspath
00316                     =    (+ch_p('/'))             [ push_back(path_, construct_<Token>()) ]
00317                       >> ( relpath
00318                          | eps_p                  [ push_back(path_, construct_<Token>()) ] )
00319                     ;
00320 
00321                 balanced_tokens
00322                     =    eps_p                    [ pos_ = positionOf(arg1) ]
00323                       >> ch_p('(')                [ token_ = construct_<Token>(
00324                                                         Token::ArgumentGroupOpen,
00325                                                         "(",
00326                                                         pos_) ]
00327                                                   [ bind(&PD::pushToken)(d_, token_) ]
00328                       >> * token
00329                       >> eps_p                    [ pos_ = positionOf(arg1) ]
00330                       >> closing_paren_expected(ch_p(')'))
00331                                                   [ token_ = construct_<Token>(
00332                                                         Token::ArgumentGroupClose,
00333                                                         ")",
00334                                                         pos_) ]
00335                                                   [ bind(&PD::pushToken)(d_, token_) ]
00336                     ;
00337 
00338                 token
00339                     =    simple_argument          [ bind(&PD::pushToken)(d_, token_) ]
00340                     |    punctuation              [ bind(&PD::pushToken)(d_, token_) ]
00341                     |    balanced_tokens
00342                     ;
00343 
00344                 punctuation             // Returns value in context.str
00345                     =    eps_p                      [ pos_ = positionOf(arg1) ]
00346                       >> (
00347                            ch_p('/')                [ token_ = construct_<Token>(
00348                                                           Token::PathSeparator,
00349                                                           "/") ]
00350                          | ch_p('{')                [ token_ = construct_<Token>(
00351                                                           Token::DirectoryGroupOpen,
00352                                                           "{") ]
00353                          | ch_p('}')                [ token_ = construct_<Token>(
00354                                                           Token::DirectoryGroupClose,
00355                                                           "}") ]
00356                          | ch_p(';')                [ token_ = construct_<Token>(
00357                                                           Token::CommandTerminator,
00358                                                           ";") ]
00359                          | self.punctuation_p       [ token_ = construct_<Token>(
00360                                                           Token::OtherPunctuation,
00361                                                           construct_<std::string>(1u, arg1),
00362                                                           pos_) ]
00363                         )
00364                     ;
00365 
00366                 word                    // Returns value in context.token
00367                     =    eps_p                    [ pos_ = positionOf(arg1) ]
00368                       >> lexeme_d
00369                          [
00370                              (+ self.word_p)      [ str_ = construct_<std::string>(arg1, arg2) ]
00371                          ]
00372                       >> eps_p                    [ token_ = construct_<Token>(
00373                                                         Token::Word,
00374                                                         str_,
00375                                                         pos_) ]
00376                     ;
00377 
00378                 word_or_string
00379                     =    word
00380                     |    string
00381                     ;
00382 
00383                 hexbyte
00384                     =    uint_parser<char, 16, 2, 2>()
00385                                                   [ push_back(str_, arg1) ]
00386                     ;
00387 
00388                 statement_end
00389                     =    if_p(var(self.incremental)) [
00390                                ch_p(';')
00391                          ]
00392                          .else_p [
00393                                ch_p(';')
00394                              | end_p
00395                          ]
00396                     ;
00397 
00398                 skip
00399                     =    self.space_p | comment_p('#')
00400                     ;
00401 
00402                 //-/////////////////////////////////////////////////////////////////////////////////
00403 
00404                 start_parsers(
00405                     command,            // CommandParser
00406                     skip,               // SkipParser
00407                     arguments,          // ArgumentsParser
00408                     opt_path            // PathParser
00409                 );
00410 
00411                 BOOST_SPIRIT_DEBUG_TRACE_RULE(command,1);
00412                 BOOST_SPIRIT_DEBUG_TRACE_RULE(path,1);
00413                 BOOST_SPIRIT_DEBUG_TRACE_RULE(argument,1);
00414                 BOOST_SPIRIT_DEBUG_TRACE_RULE(word,1);
00415                 BOOST_SPIRIT_DEBUG_TRACE_RULE(string,1);
00416                 BOOST_SPIRIT_DEBUG_TRACE_RULE(hexstring,1);
00417                 BOOST_SPIRIT_DEBUG_TRACE_RULE(token,1);
00418                 BOOST_SPIRIT_DEBUG_TRACE_RULE(punctuation,1);
00419                 BOOST_SPIRIT_DEBUG_TRACE_RULE(hexbyte,1);
00420                 BOOST_SPIRIT_DEBUG_TRACE_RULE(balanced_tokens,1);
00421                 BOOST_SPIRIT_DEBUG_TRACE_RULE(simple_argument,1);
00422                 BOOST_SPIRIT_DEBUG_TRACE_RULE(complex_argument,1);
00423                 BOOST_SPIRIT_DEBUG_TRACE_RULE(builtin,1);
00424                 BOOST_SPIRIT_DEBUG_TRACE_RULE(commands,1);
00425                 BOOST_SPIRIT_DEBUG_TRACE_RULE(block,1);
00426                 BOOST_SPIRIT_DEBUG_TRACE_RULE(statement,1);
00427                 BOOST_SPIRIT_DEBUG_TRACE_RULE(relpath,1);
00428                 BOOST_SPIRIT_DEBUG_TRACE_RULE(abspath,1);
00429             }
00430         };
00431     };
00432 
00433     template <class PD> boost_spirit::chset<> CommandGrammar<PD>::special_p (
00434         "/(){};\"");
00435     template <class PD> boost_spirit::chset<> CommandGrammar<PD>::punctuation_p (
00436         ",=");
00437     template <class PD> boost_spirit::chset<> CommandGrammar<PD>::space_p (
00438         " \t\n\r");
00439     template <class PD> boost_spirit::chset<> CommandGrammar<PD>::invalid_p (
00440         (boost_spirit::chset<>('\0') | boost_spirit::chset<>("\x01-\x20")) - space_p );
00441     template <class PD> boost_spirit::chset<> CommandGrammar<PD>::word_p (
00442         boost_spirit::anychar_p - special_p - punctuation_p - space_p - invalid_p);
00443     template <class PD> boost_spirit::distinct_parser<> CommandGrammar<PD>::keyword_p (
00444         word_p | boost_spirit::ch_p('/'));
00445 
00446 #endif
00447 
00448 }}}
00449 
00450 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00451 #endif
00452 
00453 
00454 // Local Variables:
00455 // mode: c++
00456 // fill-column: 100
00457 // comment-column: 40
00458 // c-file-style: "senf"
00459 // indent-tabs-mode: nil
00460 // ispell-local-dictionary: "american"
00461 // compile-command: "scons -u test"
00462 // End:

Contact: senf-dev@lists.berlios.de | © 2006-2010 Fraunhofer Institute for Open Communication Systems, Network Research