Console: Added Module
[senf.git] / Console / Parse.ih
1 // $Id$
2 //
3 // Copyright (C) 2008 
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
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.
12 //
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.
17 //
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.
22
23 /** \file
24     \brief Parse internal header */
25
26 #ifndef IH_Parse_
27 #define IH_Parse_ 1
28
29 // Custom includes
30 #include <boost/regex.hpp>
31 #include <boost/spirit.hpp>
32 #include <boost/spirit/utility/regex.hpp>
33 #include <boost/spirit/actor.hpp>
34 #include <boost/bind.hpp>
35 #include <boost/function.hpp>
36 #include <boost/ref.hpp>
37
38 ///////////////////////////////ih.p////////////////////////////////////////
39
40 namespace senf {
41 namespace console {
42 namespace detail {
43
44     struct append_action
45     {
46         template <class T, class Value>
47         void act(T & ref, Value const & value) const
48             { ref += T(1, value); }
49
50         template <class T, class Iterator>
51         void act(T & ref, Iterator const & f, Iterator const & l) const
52             { ref += T(f,l); }
53     };
54
55     template <class T>
56     inline boost::spirit::ref_value_actor<T, append_action> 
57     append_a(T & ref)
58     {
59         return boost::spirit::ref_value_actor<T, append_action>(ref);
60     }
61     
62     template <class T, class Value>
63     inline boost::spirit::ref_const_ref_actor<T, Value, append_action> 
64     append_a(T & ref, Value const & value)
65     {
66         return boost::spirit::ref_const_ref_actor<T, Value, append_action>(ref, value);
67     }
68
69     template <class ParseDispatcher>
70     struct CommandGrammar : boost::spirit::grammar<CommandGrammar<ParseDispatcher> >
71     {
72         ///////////////////////////////////////////////////////////////////////////
73         // The parse context (variables needed while parsing)
74
75         struct Context {
76             std::string str;
77             char ch;
78         };
79
80         Context & context;
81
82         ///////////////////////////////////////////////////////////////////////////
83         // Dispatching semantic actions
84
85         ParseDispatcher & dispatcher;
86
87         struct Dispatch_actor
88         {
89             Dispatch_actor(boost::function<void ()> fn_) : fn (fn_) {}
90
91             template <class Value>
92             void operator()(Value const & value) const
93                 { fn(); }
94
95             template <class Iterator>
96             void operator()(Iterator const & f, Iterator const & l) const
97                 { fn(); }
98
99             boost::function<void ()> fn;
100         };
101         
102         template <class Callback>
103         Dispatch_actor dispatch(Callback cb) const
104             { return Dispatch_actor(boost::bind(cb, boost::ref(dispatcher))); }
105
106         template <class Callback, class Arg>
107         Dispatch_actor dispatch(Callback cb, Arg const & arg) const
108             { return Dispatch_actor(boost::bind(cb, boost::ref(dispatcher), arg)); }
109
110         ///////////////////////////////////////////////////////////////////////////
111
112         CommandGrammar(ParseDispatcher & d, Context & c) 
113             : context(c), dispatcher(d) {}
114
115         template <class Scanner>
116         struct definition
117         {
118             boost::spirit::rule<Scanner> command, path, argument, word, string, hexstring, token;
119             boost::spirit::rule<Scanner> punctuation, hexbyte, balanced_tokens, simple_argument;
120             boost::spirit::rule<Scanner> complex_argument;
121
122             definition(CommandGrammar const & self) {
123                 using namespace boost::spirit;
124                 typedef ParseDispatcher PD;
125                 
126                 command 
127                     =    path                     [ self.dispatch(&PD::beginCommand, 
128                                                                   boost::cref(self.context.str)) ]
129                       >> * argument
130                       >> ! ch_p(';')
131                       >> eps_p                    [ self.dispatch(&PD::endCommand) ]
132                     ;
133
134                 argument
135                     =    simple_argument          [ self.dispatch(&PD::pushArgument, 
136                                                                   boost::cref(self.context.str)) ]
137                     |    complex_argument
138                     ;
139                 
140                 simple_argument         // All these return their value in context.str
141                     =    string
142                     |    hexstring
143                     |    path
144                     ;
145                 
146                 complex_argument        // Argument consists of multiple tokens
147                     =    ch_p('(')                [ self.dispatch(&PD::openGroup) ]
148                        >> * token
149                        >> ch_p(')')               [ self.dispatch(&PD::closeGroup) ]
150                     ;
151
152                 string                  // Returns value in context.str
153                     =    eps_p                    [ clear_a(self.context.str) ]
154                       >> lexeme_d
155                          [
156                              ch_p('"')
157                           >> * ( ( lex_escape_ch_p[ assign_a(self.context.ch) ] 
158                                    - '"' 
159                                  )                [ append_a(self.context.str,
160                                                              self.context.ch) ] 
161                                )
162                           >> ch_p('"')
163                          ]
164                     ;
165
166                 hexstring               // Returns value in context.str
167                     =    eps_p                    [ clear_a(self.context.str) ]
168                       >> confix_p( "x\"", * hexbyte, '"' )
169                     ;
170
171                 path                    // Returns value in context.str
172                     =    eps_p                    [ clear_a(self.context.str) ]
173                       >> ( ! ch_p('/')            [ append_a(self.context.str) ] 
174                          ) 
175                       >> (   word                 [ append_a(self.context.str) ] 
176                            % ch_p('/')            [ append_a(self.context.str) ] 
177                          )
178                     ;
179
180                 balanced_tokens 
181                     =    ch_p('(')                [ self.dispatch(&PD::pushPunctuation, "(") ]
182                       >> * token
183                       >> ch_p(')')                [ self.dispatch(&PD::pushPunctuation, ")") ]
184                     ;
185
186                 token
187                     =    simple_argument          [ self.dispatch(&PD::pushWord, 
188                                                                   boost::cref(self.context.str)) ]
189                     |    punctuation              [ self.dispatch(&PD::pushPunctuation,
190                                                                   boost::cref(self.context.str)) ]
191                     |    balanced_tokens
192                     ;
193
194                 punctuation             // Returns value in context.str
195                     =    regex_p("[,=]")          [ assign_a(self.context.str) ]
196                     ;
197
198                 word
199                     =    regex_p("[^ \t\n\r;,=(){}/\"]+")
200                     ;
201
202                 hexbyte
203                     =    uint_parser<char, 16, 2, 2>()
204                                                   [ append_a(self.context.str) ]
205                     ;
206
207                 BOOST_SPIRIT_DEBUG_RULE(command);
208                 BOOST_SPIRIT_DEBUG_RULE(path);
209                 BOOST_SPIRIT_DEBUG_RULE(argument);
210                 BOOST_SPIRIT_DEBUG_RULE(word);
211                 BOOST_SPIRIT_DEBUG_RULE(string);
212                 BOOST_SPIRIT_DEBUG_RULE(hexstring);
213                 BOOST_SPIRIT_DEBUG_RULE(token);
214                 BOOST_SPIRIT_DEBUG_RULE(punctuation);
215                 BOOST_SPIRIT_DEBUG_RULE(hexbyte);
216                 BOOST_SPIRIT_DEBUG_RULE(balanced_tokens);
217                 BOOST_SPIRIT_DEBUG_RULE(simple_argument);
218                 BOOST_SPIRIT_DEBUG_RULE(complex_argument);
219             }
220
221             boost::spirit::rule<Scanner> const & start() const { return command; }
222         };
223     };
224
225     struct SkipGrammar
226         : public boost::spirit::grammar<SkipGrammar>
227     {
228         template <class Scanner>
229         struct definition
230         {
231             boost::spirit::rule<Scanner> rule;
232
233             definition(SkipGrammar const & self) {
234                 rule 
235                     =    boost::spirit::regex_p("[ \t]+") 
236                     |    boost::spirit::comment_p('#')
237                     ;
238             }
239
240             boost::spirit::rule<Scanner> const & start() const { return rule; }
241         };
242     };
243
244 }}}
245
246 ///////////////////////////////ih.e////////////////////////////////////////
247 #endif
248
249 \f
250 // Local Variables:
251 // mode: c++
252 // fill-column: 100
253 // comment-column: 40
254 // c-file-style: "senf"
255 // indent-tabs-mode: nil
256 // ispell-local-dictionary: "american"
257 // compile-command: "scons -u test"
258 // End: