]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================== |
2 | Copyright (c) 2006 Tobias Schwinger | |
3 | http://spirit.sourceforge.net/ | |
4 | ||
5 | Distributed under the Boost Software License, Version 1.0. (See accompanying | |
6 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
7 | ==============================================================================*/ | |
8 | // The comment below contains a unnamed 'namespace {', which is flagged by the | |
9 | // Boost inspect tool as a violation of common C++ programming rules. Since it's | |
10 | // in a comment, well, we switch it off :-P | |
11 | // boostinspect:nounnamed | |
12 | ||
13 | // | |
14 | // About: | |
15 | // ===== | |
16 | // | |
17 | // Using a typeof operator or Boost.Typeof to automatically set the type of | |
18 | // variables (as done in the Spirit example demonstrating typeof) is by far not | |
19 | // all we can do to tighten up our grammars as there are some significant | |
20 | // drawbacks of this approach: | |
21 | // - the types complexity scales with the complexity of the grammar (sooner or | |
22 | // later hitting the limits of the compiler), | |
23 | // - recursive grammars are not possible, and | |
24 | // - all parser objects are embedded by value. | |
25 | // | |
26 | // The Spirit documentation therefore recommends creating custom parser classes | |
27 | // (derived from the a sub_grammar template): | |
28 | // | |
29 | // http://www.boost.org/libs/spirit/doc/techniques.html#no_rules | |
30 | // http://www.boost.org/libs/spirit/doc/techniques.html#typeof | |
31 | // | |
32 | // In practice manually applying this technique leads to rather lengthy code and | |
33 | // overthis requires the user to have a solid understanding of Spirit details. | |
34 | // | |
35 | // Here is a generalized, macro-based approach to easily create typeof-based | |
36 | // grammars that can be recursive and arbitrarily complex. | |
37 | // | |
38 | // | |
39 | // Quick manual: | |
40 | // ============ | |
41 | // | |
42 | // 1. Setup | |
43 | // | |
44 | // Before the rule parser macro (the protagonist of the facility) can be used | |
45 | // the user must define the macro BOOST_SPIRIT__NAMESPACE (note the double | |
46 | // underscore characeter) and setup a registration group for Boost.Typeof. | |
47 | // | |
48 | // Examples: | |
49 | // | |
50 | // // should come after regular #includeS | |
51 | // #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() | |
52 | // | |
53 | // // [...] | |
54 | // | |
55 | // #define BOOST_SPIRIT__NAMESPACE (2,(my_project, my_module)) | |
56 | // // | | +- outer +- inner | |
57 | // // ! space ! -+ | namespace namespace | |
58 | // // | | |
59 | // // +--- number of nested namespaces | |
60 | // | |
61 | // namespace my_project { namespace my_module { | |
62 | // | |
63 | // // [...] | |
64 | // | |
65 | // --- | |
66 | // | |
67 | // // should come after regular #includeS | |
68 | // #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() | |
69 | // | |
70 | // // [...] | |
71 | // | |
72 | // #define BOOST_SPIRIT__NAMESPACE (2,(my_project, (anonymous) )) | |
73 | // | |
74 | // namespace my_project { namespace { | |
75 | // | |
76 | // // [...] | |
77 | // | |
78 | // --- | |
79 | // | |
80 | // // should come after regular #includeS | |
81 | // #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() | |
82 | // | |
83 | // // [...] | |
84 | // | |
85 | // | |
86 | // #define BOOST_SPIRIT__NAMESPACE - | |
87 | // // we're working at root namespace | |
88 | // | |
89 | // | |
90 | // Why do I have to do this? | |
91 | // | |
92 | // Boost.Typeof needs to assign a unique ID for each registration. This ID is | |
93 | // created composed of the line number and the registration group. The | |
94 | // facility performs Typeof registration and thus requires the source file to | |
95 | // have its own registration group. Further Boost.Typeof requires registration | |
96 | // to happen at root namespace so we have to close and reopen the namespace | |
97 | // we're in. | |
98 | // | |
99 | // | |
100 | // 2. The rule parser macro | |
101 | // | |
102 | // A simple rule parser definition looks like that: | |
103 | // | |
104 | // // we're at namespace scope here | |
105 | // | |
106 | // // Skip parser for C/C++ comments and whitespace | |
107 | // BOOST_SPIRIT_RULE_PARSER(skipper, | |
108 | // -,-,-, | |
109 | // | |
110 | // +( confix_p("//",*anychar_p,eol_p) | |
111 | // | confix_p("/*",*anychar_p,"*/") | |
112 | // | space_p | |
113 | // ) | |
114 | // ) | |
115 | // | |
116 | // Now we can use 'skipper' in other Spirit expressions. | |
117 | // | |
118 | // The code above creates a parser (template) class 'skpper_t' and (in this | |
119 | // case, because there are no parameters) a static const instance 'skipper' of | |
120 | // that class. The class is automatically registered with Boost.Typeof. The type | |
121 | // name our parser is skipper_t here. | |
122 | // | |
123 | // | |
124 | // 2.1. Parametrized rule parsers | |
125 | // | |
126 | // Rule parser definitions can have parameters. | |
127 | // | |
128 | // Parameters are passed to the BOOST_SPIRIT_RULE_PARSER macro as its second | |
129 | // argument (just pass '-' if there are no parameters) with the following | |
130 | // format: | |
131 | // | |
132 | // (N,( param1,param2, / ... / paramN )) | |
133 | // +-- number of parameters | |
134 | // | |
135 | // Example of a whole rule parser: | |
136 | // | |
137 | // BOOST_SPIRIT_RULE_PARSER(new_name, | |
138 | // (1,( symbol_table )),-,-, | |
139 | // | |
140 | // lexeme_d[ (alpha_p >> *alnum_p)[ symbol_table.add ] ] | |
141 | // ) | |
142 | // | |
143 | // The expression 'new_name(my_symbols)' parses a string literal and adds it to | |
144 | // the symbol table 'my_symbols'. | |
145 | // | |
146 | // The rule parser macro creates a function template as called 'new_name' that | |
147 | // takes one parameter of deduced reference type and returns a specialization of | |
148 | // 'new_name_t' in this case. | |
149 | // | |
150 | // Since parsers that require to be fast and lightweight often also require to | |
151 | // be reentrant, it's quite common to pass in some semantic controller (the | |
152 | // symbol table in the example above). | |
153 | // However, parameters are templated so they can be anything (including parsers | |
154 | // of course) so refactoring tasks can be abstracted with rule parsers as well. | |
155 | // | |
156 | // BOOST_SPIRIT_RULE_PARSER(enumeration_parser, | |
157 | // (2,( element_parser, delimiter_parser )),-,-, | |
158 | // | |
159 | // element_parser >> *(delimiter_parser >> element_parser) | |
160 | // ) | |
161 | // | |
162 | // The expression 'enumeration_parser(int_p[ some_action ], ',')' creates a | |
163 | // parser for a comma-separated list of integers. | |
164 | // | |
165 | // | |
166 | // 2.2. Rule parsrs and semantic actions | |
167 | // | |
168 | // While semantic actions can be globally attached to a rule parser or passed | |
169 | // to a parametrized rule parser as (part of) an argument, even more control is | |
170 | // possible by using action placeholders. E.g: | |
171 | // | |
172 | // BOOST_SPIRIT_ACTION_PLACEHOLDER(int_action) | |
173 | // | |
174 | // BOOST_SPIRIT_RULE_PARSER(int_list, | |
175 | // -,(1,( int_action )),-, | |
176 | // | |
177 | // int_p[ int_action ] >> *(',' >> int_p[ int_action ]) | |
178 | // ) | |
179 | // | |
180 | // The expression 'int_list[ my_action ]' parses a comma separated list of | |
181 | // integers and calls 'my_action' for every integer parsed therein. | |
182 | // | |
183 | // Of course multiple actions can be attached to one placeholder as usual (in | |
184 | // this case 'int_list[ my_action1 ][ my_action2 ] would call two actions). | |
185 | // | |
186 | // Further there can be multiple action placeholders for a single rule parser: | |
187 | // | |
188 | // BOOST_SPIRIT_ACTION_PLACEHOLDER(feed_int) | |
189 | // BOOST_SPIRIT_ACTION_PLACEHOLDER(next_int) | |
190 | // | |
191 | // BOOST_SPIRIT_RULE_PARSER(int_list, | |
192 | // -,(2,( feed_int, next_int )),-, | |
193 | // | |
194 | // int_p[ feed_int ] >> *(',' >> int_p[ next_int ][ feed_int ]) | |
195 | // ) | |
196 | // | |
197 | // The expression 'int_list[ (feed_int = my_action1), (next_int = my_action2) ]' | |
198 | // creates a parser for a comma separated list of integers with the actions | |
199 | // attached appropriately. | |
200 | // | |
201 | // int_list[ feed_int = my_action1,my_action2, next_int = my_action3 ] | |
202 | // | |
203 | // works too (in this case the action placeholder 'feed_int' has two actions | |
204 | // attached to it). | |
205 | // | |
206 | // You can both override and append actions associated with an action | |
207 | // placeholder: | |
208 | // | |
209 | // var = int_list[ feed_int = my_action1, next_int = my_action2 ] | |
210 | // | |
211 | // // [...] | |
212 | // | |
213 | // ... var[ feed_int = another_action ] | |
214 | // // 'another_action' overrides the actions previously attached to 'feed_int' | |
215 | // | |
216 | // ... var[ next_int += another_action ] | |
217 | // // 'another_action' is appended to the list of actions attached to | |
218 | // // 'next_int' | |
219 | // | |
220 | // Action placeholders are not entirely for free -- they add to the size and the | |
221 | // initialization time of the rule parser. However, the impact on an already | |
222 | // initialized rule parser instance should be quite small. | |
223 | // | |
224 | // | |
225 | // 2.3. Member variables | |
226 | // | |
227 | // You can add member variables to the rule parser class using the third | |
228 | // parameter of the rule parser macro: | |
229 | // | |
230 | // BOOST_SPIRIT_RULE_PARSER( calc, | |
231 | // -, | |
232 | // -, | |
233 | // (3,( ((subrule<0>),expression,()), | |
234 | // ((subrule<1>),term,()), | |
235 | // ((subrule<2>),factor,() )) ), | |
236 | // | |
237 | // // [...] | |
238 | // | |
239 | // adds three subrules to the rule parser. | |
240 | // Each parameter must have the following type to allow commas to be handled | |
241 | // safely from within the preprocessing code: | |
242 | // | |
243 | // ((type)),name,(constructor argument(s))) | |
244 | // | |
245 | // | |
246 | // 2.4. The opaque rule parser | |
247 | // | |
248 | // Rule parsers usually are templates. Building large grammars pushes the | |
249 | // compiler really hard (and eventually to its limits) because of the | |
250 | // metafunction complexity involved. | |
251 | // If a rule parser without parameters and action placeholders is defined, a | |
252 | // non-template class is created. Non-templated rule parsers can also be created | |
253 | // explicitly by using BOOST_SPIRIT_OPAQUE_RULE_PARSER. | |
254 | // Opaque rule parsers can have parameters and member variables (note: no action | |
255 | // placeholders are possible). The parameters of an opaque rule parsers are | |
256 | // strictly typed, e.g: | |
257 | // | |
258 | // BOOST_SPIRIT_OPAQUE_RULE_PARSER(new_identifier, | |
259 | // (1,( ((my_symbol_table_t &),symbol_table) )) | |
260 | // ,-, | |
261 | // (alpha_p >> *alnum_p) [ symbol_table.add ] | |
262 | // ) | |
263 | // | |
264 | // Note it's also possible to have opaque rule parsers accept parameters of | |
265 | // non-const reference types which is not possible with regular rule parsers. | |
266 | // | |
267 | // | |
268 | // 3. Utilities for by-reference embedding | |
269 | // | |
270 | // When using parsers mutiple times or recursively it can be helpful to embed | |
271 | // them by-reference into the final parser expression. | |
272 | // For this purpose the library provides a wrapper template 'parser_reference'. | |
273 | // There is also a function template to create a wrapped parser which can deduce | |
274 | // the parser's type from its argument. | |
275 | // | |
276 | // --- --- - - --- - - --- - - - - --- - - - - - - - - - - - - - - - - - - - - - | |
277 | #if !defined(BOOST_SPIRIT_UTILITY_RULE_PARSER_HPP_INCLUDED) | |
278 | # define BOOST_SPIRIT_UTILITY_RULE_PARSER_HPP_INCLUDED | |
279 | //============================================================================== | |
280 | // Dependencies | |
281 | //============================================================================== | |
282 | # include <boost/config.hpp> | |
283 | # include <boost/detail/workaround.hpp> | |
284 | # include <boost/call_traits.hpp> | |
285 | # include <boost/typeof/typeof.hpp> | |
286 | # include <boost/spirit/home/classic/namespace.hpp> | |
287 | # include <boost/spirit/home/classic/core/parser.hpp> | |
288 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
289 | # include <boost/preprocessor/cat.hpp> | |
290 | # include <boost/preprocessor/seq/seq.hpp> | |
291 | # include <boost/preprocessor/seq/for_each_i.hpp> | |
292 | # include <boost/preprocessor/tuple/eat.hpp> | |
293 | # include <boost/preprocessor/tuple/to_seq.hpp> | |
294 | # include <boost/preprocessor/array/size.hpp> | |
295 | # include <boost/preprocessor/control/if.hpp> | |
296 | # include <boost/preprocessor/control/iif.hpp> | |
297 | # include <boost/preprocessor/control/expr_iif.hpp> | |
298 | # include <boost/preprocessor/logical/or.hpp> | |
299 | # include <boost/preprocessor/logical/nor.hpp> | |
300 | # include <boost/preprocessor/logical/not.hpp> | |
301 | # include <boost/preprocessor/logical/compl.hpp> | |
302 | # include <boost/preprocessor/arithmetic/inc.hpp> | |
303 | # include <boost/preprocessor/arithmetic/dec.hpp> | |
304 | # include <boost/preprocessor/arithmetic/add.hpp> | |
305 | # include <boost/preprocessor/detail/is_unary.hpp> | |
306 | # include <boost/preprocessor/detail/is_binary.hpp> | |
307 | # include <boost/preprocessor/repetition/repeat.hpp> | |
308 | # include <boost/preprocessor/repetition/enum_params.hpp> | |
309 | # include <boost/preprocessor/repetition/enum_binary_params.hpp> | |
310 | # include <boost/preprocessor/repetition/enum_shifted_params.hpp> | |
311 | # include <boost/preprocessor/repetition/enum_trailing_params.hpp> | |
312 | # include <boost/preprocessor/punctuation/comma.hpp> | |
313 | # include <boost/preprocessor/punctuation/comma_if.hpp> | |
314 | # include <boost/preprocessor/facilities/empty.hpp> | |
315 | # include <boost/preprocessor/facilities/identity.hpp> | |
316 | # include <boost/preprocessor/facilities/intercept.hpp> | |
317 | //============================================================================== | |
318 | // Interface | |
319 | //============================================================================== | |
320 | // Creates a rule parser. Use at namespace scope. | |
321 | # define BOOST_SPIRIT_RULE_PARSER(name,params,actions,members,rule) \ | |
322 | BOOST_SPIRIT_RP_IMPL_I(name,params,actions,members,rule) | |
323 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
324 | // Creates a non-templated rule parser. Use at namespace scope. | |
325 | # define BOOST_SPIRIT_OPAQUE_RULE_PARSER(name,params,members,rule) \ | |
326 | BOOST_SPIRIT_RP_OPAQUE_IMPL_I(name,params,members,rule) | |
327 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
328 | // Defines an action placeholder. Use at namespace scope. | |
329 | # define BOOST_SPIRIT_ACTION_PLACEHOLDER(name) \ | |
330 | BOOST_SPIRIT_RP_AP_IMPL(name,::BOOST_SPIRIT_CLASSIC_NS::type_of) | |
331 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
332 | // Utilities to embed parsers by reference. | |
333 | namespace boost | |
334 | { | |
335 | namespace spirit | |
336 | { | |
337 | BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN | |
338 | ||
339 | template<class P> class parser_reference; | |
340 | template<class P> parser_reference<P> embed_by_reference(parser<P> const &); | |
341 | ||
342 | BOOST_SPIRIT_CLASSIC_NAMESPACE_END | |
343 | } | |
344 | } | |
345 | //============================================================================== | |
346 | // Implementation | |
347 | //============================================================================== | |
348 | #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() | |
349 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
350 | // RP_REGISTER_TEMPLATE | |
351 | // | |
352 | // Boost.Typeof registration from within BOOST_SPIRIT__NAMESPACE | |
353 | # define BOOST_SPIRIT_RP_REGISTER_TEMPLATE(name,params) \ | |
354 | BOOST_SPIRIT_RP_EMIT(NS_CLOSE,BOOST_SPIRIT__NAMESPACE,-) \ | |
355 | BOOST_TYPEOF_REGISTER_TEMPLATE( \ | |
356 | BOOST_SPIRIT_RP_EMIT(NS_QUALIFY,BOOST_SPIRIT__NAMESPACE,-) name, \ | |
357 | params) \ | |
358 | BOOST_SPIRIT_RP_EMIT(NS_OPEN,BOOST_SPIRIT__NAMESPACE,-) | |
359 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
360 | // RP_REGISTER_TYPE | |
361 | // | |
362 | // Boost.Typeof registration from within BOOST_SPIRIT__NAMESPACE | |
363 | # define BOOST_SPIRIT_RP_REGISTER_TYPE(name) \ | |
364 | BOOST_SPIRIT_RP_EMIT(NS_CLOSE,BOOST_SPIRIT__NAMESPACE,-) \ | |
365 | BOOST_TYPEOF_REGISTER_TYPE( \ | |
366 | BOOST_SPIRIT_RP_EMIT(NS_QUALIFY,BOOST_SPIRIT__NAMESPACE,-) name ) \ | |
367 | BOOST_SPIRIT_RP_EMIT(NS_OPEN,BOOST_SPIRIT__NAMESPACE,-) | |
368 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
369 | // RP_AP_IMPL | |
370 | // | |
371 | // The action placeholder definition | |
372 | # define BOOST_SPIRIT_RP_AP_IMPL(name,ns) \ | |
373 | namespace __action_placeholder \ | |
374 | { \ | |
375 | struct name \ | |
376 | { \ | |
377 | template<typename Action> \ | |
378 | ns :: action_chain< name, ns :: replace, Action> \ | |
379 | operator=(Action const & __a) const \ | |
380 | { return ns :: action_chain< name, ns :: replace, Action>(__a); } \ | |
381 | \ | |
382 | template<typename Action> \ | |
383 | ns :: action_chain< name, ns :: append, Action> \ | |
384 | operator+=(Action const & __a) const \ | |
385 | { return ns :: action_chain< name, ns :: append, Action> (__a); } \ | |
386 | }; \ | |
387 | } \ | |
388 | __action_placeholder:: name const name = __action_placeholder:: name (); | |
389 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
390 | // RP_IMPL_I | |
391 | // | |
392 | // Does some precalculation so RP_IMPL_II can look cleaner | |
393 | # define BOOST_SPIRIT_RP_IMPL_I(name,pars,acts,mbrs,expr) \ | |
394 | BOOST_SPIRIT_RP_IMPL_II(name, name ## _t , \ | |
395 | pars, BOOST_SPIRIT_RP_ARRAY_SIZE(pars), \ | |
396 | acts, BOOST_SPIRIT_RP_ARRAY_SIZE(acts), \ | |
397 | mbrs, BOOST_SPIRIT_RP_ARRAY_SIZE(mbrs), expr) | |
398 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
399 | // RP_IMPL_II | |
400 | # define BOOST_SPIRIT_RP_IMPL_II(name,name_t,pars,np,acts,na,mbrs,nm,x) \ | |
401 | BOOST_PP_IIF(BOOST_PP_OR(np,na),BOOST_SPIRIT_RP_IMPL_III, \ | |
402 | BOOST_SPIRIT_RP_OPAQUE_IMPL_II) \ | |
403 | (name,name_t,pars,np,acts,na,mbrs,nm,x) | |
404 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
405 | // RP_IMPL_III | |
406 | // | |
407 | // The rule parser definition | |
408 | # define BOOST_SPIRIT_RP_IMPL_III(name,name_t,pars,np,acts,na,mbrs,nm,x) \ | |
409 | \ | |
410 | template< BOOST_SPIRIT_RP_TPL_PARAMS(pars,acts,typename __,1) > \ | |
411 | class name_t \ | |
412 | : public ::BOOST_SPIRIT_CLASSIC_NS::parser< name_t \ | |
413 | < BOOST_SPIRIT_RP_TPL_PARAMS(pars,acts,__,0) > > \ | |
414 | { \ | |
415 | class __rule \ | |
416 | { \ | |
417 | BOOST_SPIRIT_RP_EMIT(PM_STATIC,pars,__T) \ | |
418 | BOOST_SPIRIT_RP_EMIT(AP_STATIC,acts,-) \ | |
419 | BOOST_SPIRIT_RP_EMIT(MV_STATIC,mbrs,BOOST_PP_IDENTITY(typename)) \ | |
420 | public: \ | |
421 | BOOST_TYPEOF_NESTED_TYPEDEF_TPL(__expr, \ | |
422 | ::BOOST_SPIRIT_CLASSIC_NS::type_of::depend_on_type<__Dummy>(x) ) \ | |
423 | }; \ | |
424 | \ | |
425 | public: \ | |
426 | \ | |
427 | typedef name_t self_t; \ | |
428 | typedef typename __rule::__expr::type::parser_category_t \ | |
429 | parser_category_t; \ | |
430 | \ | |
431 | BOOST_PP_EXPR_IIF(BOOST_PP_NOR(np,na),typedef self_t const & embed_t;) \ | |
432 | \ | |
433 | protected: \ | |
434 | \ | |
435 | BOOST_SPIRIT_RP_EMIT(MV_NONSTATIC,mbrs,BOOST_PP_IDENTITY(typename)) \ | |
436 | BOOST_SPIRIT_RP_IF(na,SPIRIT_RP_AP_EXTRA_MBRS,2)(np,na) \ | |
437 | \ | |
438 | typename __rule::__expr::type::embed_t __parser; \ | |
439 | \ | |
440 | public: \ | |
441 | \ | |
442 | explicit name_t ( BOOST_SPIRIT_RP_CTOR(PARAMS,pars,np,acts) ) \ | |
443 | : BOOST_SPIRIT_RP_EMIT(MV_CTOR_INIT_LIST,mbrs,-) \ | |
444 | BOOST_PP_COMMA_IF(nm) \ | |
445 | BOOST_SPIRIT_RP_IF(na,SPIRIT_RP_CTOR_COMMA,4)(INIT_LIST,pars,np,acts)\ | |
446 | __parser(x) \ | |
447 | { } \ | |
448 | \ | |
449 | name_t( name_t const & that) \ | |
450 | : BOOST_SPIRIT_RP_EMIT(MV_CTOR_COPY_INIT_LIST,mbrs,that) \ | |
451 | BOOST_PP_COMMA_IF(nm) \ | |
452 | BOOST_SPIRIT_RP_IF(na,SPIRIT_RP_CTOR_COMMA,4) \ | |
453 | (COPY_INIT_LIST,pars,np,acts) \ | |
454 | __parser(that.__parser) \ | |
455 | { } \ | |
456 | \ | |
457 | template<typename Scanner> struct result \ | |
458 | { \ | |
459 | typedef typename ::BOOST_SPIRIT_CLASSIC_NS::parser_result< \ | |
460 | typename __rule::__expr::type, Scanner>::type type; \ | |
461 | }; \ | |
462 | \ | |
463 | template<typename Scanner> \ | |
464 | typename ::BOOST_SPIRIT_CLASSIC_NS::parser_result<self_t, Scanner>::type \ | |
465 | parse(Scanner const & s) const { return __parser.parse(s); } \ | |
466 | \ | |
467 | BOOST_SPIRIT_RP_IF(na,SPIRIT_RP_AP_HANDLER,5) \ | |
468 | (name_t,np,acts,na,::BOOST_SPIRIT_CLASSIC_NS::type_of) \ | |
469 | }; \ | |
470 | \ | |
471 | BOOST_PP_IF(np,BOOST_SPIRIT_RP_GEN_FUNC,BOOST_SPIRIT_RP_GLOB_VAR) \ | |
472 | (name,name_t,np,na) \ | |
473 | BOOST_SPIRIT_RP_REGISTER_TEMPLATE \ | |
474 | (name_t,BOOST_PP_INC(BOOST_PP_ADD(np,na))) | |
475 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
476 | // RP_OPAQUE_IMPL_I | |
477 | // | |
478 | # define BOOST_SPIRIT_RP_OPAQUE_IMPL_I(name,pars,mbrs,expr) \ | |
479 | BOOST_SPIRIT_RP_OPAQUE_IMPL_II(name, name ## _t, \ | |
480 | pars,BOOST_SPIRIT_RP_ARRAY_SIZE(pars),-,-,\ | |
481 | mbrs,BOOST_SPIRIT_RP_ARRAY_SIZE(mbrs),expr) | |
482 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
483 | // RP_OPAQUE_IMPL_II | |
484 | // | |
485 | # define BOOST_SPIRIT_RP_OPAQUE_IMPL_II(name,name_t,pars,np,_1,_2,mbrs,nm,x) \ | |
486 | class name_t; \ | |
487 | \ | |
488 | BOOST_SPIRIT_RP_REGISTER_TYPE(name_t) \ | |
489 | \ | |
490 | class name_t \ | |
491 | : public ::BOOST_SPIRIT_CLASSIC_NS::parser< name_t > \ | |
492 | { \ | |
493 | class __rule \ | |
494 | { \ | |
495 | BOOST_SPIRIT_RP_EMIT(PM_OPAQUE_STATIC,pars,-) \ | |
496 | BOOST_SPIRIT_RP_EMIT(MV_STATIC,mbrs,BOOST_PP_EMPTY) \ | |
497 | public: \ | |
498 | BOOST_TYPEOF_NESTED_TYPEDEF(__expr,x) \ | |
499 | }; \ | |
500 | \ | |
501 | public: \ | |
502 | \ | |
503 | typedef name_t self_t; \ | |
504 | typedef __rule::__expr::type::parser_category_t parser_category_t; \ | |
505 | BOOST_PP_EXPR_IIF(BOOST_PP_NOT(np),typedef self_t const & embed_t;) \ | |
506 | \ | |
507 | protected: \ | |
508 | \ | |
509 | BOOST_SPIRIT_RP_EMIT(MV_NONSTATIC,mbrs,BOOST_PP_EMPTY) \ | |
510 | \ | |
511 | __rule::__expr::type::embed_t __parser; \ | |
512 | \ | |
513 | public: \ | |
514 | \ | |
515 | explicit name_t (BOOST_SPIRIT_RP_EMIT(PM_OPAQUE_CTOR_PARAMS,pars,-)) \ | |
516 | : BOOST_SPIRIT_RP_EMIT(MV_CTOR_INIT_LIST,mbrs,-) \ | |
517 | BOOST_PP_COMMA_IF(nm) __parser(x) \ | |
518 | { } \ | |
519 | \ | |
520 | name_t(name_t const & that) \ | |
521 | : BOOST_SPIRIT_RP_EMIT(MV_CTOR_COPY_INIT_LIST,mbrs,that) \ | |
522 | BOOST_PP_COMMA_IF(nm) __parser(that.__parser) \ | |
523 | { } \ | |
524 | \ | |
525 | template<typename Scanner> struct result \ | |
526 | { \ | |
527 | typedef typename ::BOOST_SPIRIT_CLASSIC_NS::parser_result< \ | |
528 | __rule::__expr::type, Scanner>::type type; \ | |
529 | }; \ | |
530 | \ | |
531 | template<typename Scanner> \ | |
532 | typename ::BOOST_SPIRIT_CLASSIC_NS::parser_result<self_t, Scanner>::type \ | |
533 | parse(Scanner const & s) const { return __parser.parse(s); } \ | |
534 | }; \ | |
535 | \ | |
536 | BOOST_PP_IF(np,BOOST_SPIRIT_RP_GEN_OPAQUE,BOOST_SPIRIT_RP_GLOB_OPAQUE) \ | |
537 | (name,name_t,np,pars) | |
538 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
539 | // RP_AP_HANDLER | |
540 | // | |
541 | // Part of the rule parser definition for handling action placeholders | |
542 | # define BOOST_SPIRIT_RP_AP_HANDLER(name_t,np,acts,na,ns) \ | |
543 | private: \ | |
544 | template<typename A> struct __rebound_1st \ | |
545 | { \ | |
546 | typedef name_t < void BOOST_PP_ENUM_TRAILING_PARAMS(np,__T) , \ | |
547 | typename ns ::action_concatenator<__A0,A>::type \ | |
548 | BOOST_PP_COMMA_IF(BOOST_PP_DEC(na)) \ | |
549 | BOOST_PP_ENUM_SHIFTED_PARAMS(na,__A) \ | |
550 | > type; \ | |
551 | }; \ | |
552 | \ | |
553 | template<typename X> struct __rebound \ | |
554 | { \ | |
555 | typedef name_t < \ | |
556 | void BOOST_PP_ENUM_TRAILING_PARAMS(np,__T) \ | |
557 | BOOST_SPIRIT_RP_EMIT(AP_REBOUND_TPL_ARGS,acts,X) \ | |
558 | > type; \ | |
559 | }; \ | |
560 | public: \ | |
561 | template<typename A> \ | |
562 | typename __rebound_1st<A>::type const operator[](A const & a) const \ | |
563 | { \ | |
564 | return typename __rebound_1st<A>::type ( \ | |
565 | BOOST_PP_ENUM_PARAMS(np,__p) BOOST_PP_COMMA_IF(np) \ | |
566 | ns ::concatenate_actions(__a0,a) \ | |
567 | BOOST_PP_COMMA_IF(BOOST_PP_DEC(na)) \ | |
568 | BOOST_PP_ENUM_SHIFTED_PARAMS(na,__a) ); \ | |
569 | } \ | |
570 | template<class PH, ns ::action_chain_mode M, typename A> \ | |
571 | typename __rebound< ns ::action_chain<PH,M,A> >::type const \ | |
572 | operator[]( ns ::action_chain<PH,M,A> const & x) const \ | |
573 | { \ | |
574 | return typename __rebound< ns ::action_chain<PH,M,A> >::type ( \ | |
575 | BOOST_PP_ENUM_PARAMS(np,__p) BOOST_PP_COMMA_IF(np) \ | |
576 | BOOST_SPIRIT_RP_EMIT(AP_REBOUND_ARGS,acts,x) ); \ | |
577 | } \ | |
578 | template<class Head, class Tail> \ | |
579 | typename __rebound< ns ::action_chains<Head,Tail> >::type const \ | |
580 | operator[]( ns ::action_chains<Head,Tail> const & x) const \ | |
581 | { \ | |
582 | return typename __rebound< ns ::action_chains<Head,Tail> >::type ( \ | |
583 | BOOST_PP_ENUM_PARAMS(np,__p) BOOST_PP_COMMA_IF(np) \ | |
584 | BOOST_SPIRIT_RP_EMIT(AP_REBOUND_ARGS,acts,x) ); \ | |
585 | } | |
586 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
587 | // RP_AP_EXTRA_MBRS | |
588 | // | |
589 | // Extra members we need for rebinding if there are action placeholders | |
590 | # define BOOST_SPIRIT_RP_AP_EXTRA_MBRS(np,na) \ | |
591 | private: \ | |
592 | BOOST_PP_REPEAT(np,BOOST_SPIRIT_RP_PM_MBRS,-) \ | |
593 | BOOST_PP_REPEAT(na,BOOST_SPIRIT_RP_AP_MBRS,-) | |
594 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
595 | // RP_PM_MBRS | |
596 | // | |
597 | // Member variables to remember parameters if there are action placeholder | |
598 | # define BOOST_SPIRIT_RP_PM_MBRS(z,i,d) __T ## i __p ## i ; | |
599 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
600 | // RP_AP_MBRS | |
601 | // | |
602 | // Member variables to remember action placeholder substitutes | |
603 | # define BOOST_SPIRIT_RP_AP_MBRS(z,i,d) __A ## i __a ## i ; | |
604 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
605 | // RP_CTOR | |
606 | // | |
607 | // Expands to a fragment of a constructor (parameters or init-list) | |
608 | # define BOOST_SPIRIT_RP_CTOR(what,pars,np,acts) \ | |
609 | BOOST_SPIRIT_RP_EMIT(PM_CTOR_ ## what,pars,__T) \ | |
610 | BOOST_SPIRIT_RP_EMIT(AP_CTOR_ ## what,acts,np) | |
611 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
612 | // RP_CTOR_COMMA | |
613 | // | |
614 | // RP_CTOR with a trailing comma | |
615 | # define BOOST_SPIRIT_RP_CTOR_COMMA(what,pars,np,acts) \ | |
616 | BOOST_SPIRIT_RP_CTOR(what,pars,np,acts) , | |
617 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
618 | // RP_TPL_PARAMS | |
619 | // | |
620 | // Expands to the template parameters or arguments of the rule parser template | |
621 | # define BOOST_SPIRIT_RP_TPL_PARAMS(pars,acts,prefix,defaults) \ | |
622 | prefix ## Dummy \ | |
623 | BOOST_SPIRIT_RP_EMIT(PM_TEMPLATE_PARAMS,pars,prefix ## T) \ | |
624 | BOOST_SPIRIT_RP_EMIT(AP_TEMPLATE_PARAMS,acts,(prefix ## A,defaults)) | |
625 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
626 | // RP_GEN_FUNC | |
627 | // | |
628 | // Generator function | |
629 | # define BOOST_SPIRIT_RP_GEN_FUNC(name,name_t,np,na) \ | |
630 | template< BOOST_PP_ENUM_PARAMS(np,typename T) > \ | |
631 | inline name_t < void BOOST_PP_ENUM_TRAILING_PARAMS(np,T) > \ | |
632 | name( BOOST_PP_ENUM_BINARY_PARAMS(np,T, const & p) ) \ | |
633 | { return name_t < void BOOST_PP_ENUM_TRAILING_PARAMS(np,T) > \ | |
634 | (BOOST_PP_ENUM_PARAMS(np,p) BOOST_PP_ENUM_TRAILING_PARAMS(na, \ | |
635 | ::BOOST_SPIRIT_CLASSIC_NS::type_of::nop_functor() BOOST_PP_INTERCEPT) ); \ | |
636 | } | |
637 | // RP_GEN_OPAQUE | |
638 | // | |
639 | // non-templated version for opaque rule parsers. | |
640 | # define BOOST_SPIRIT_RP_GEN_OPAQUE(name,name_t,np,pars) \ | |
641 | inline name_t name( BOOST_SPIRIT_RP_EMIT(PM_OPAQUE_GEN_PARAMS,pars,p)) \ | |
642 | { return name_t (BOOST_PP_ENUM_PARAMS(np,p)); } | |
643 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
644 | // RP_GLOB_VAR | |
645 | // | |
646 | // Global variable -- used instead of the generator function if there are no | |
647 | // parameters | |
648 | # define BOOST_SPIRIT_RP_GLOB_VAR(name,name_t,np,na) \ | |
649 | static name_t <void> const name = name_t <void>(BOOST_PP_ENUM_PARAMS(na, \ | |
650 | ::BOOST_SPIRIT_CLASSIC_NS::type_of::nop_functor() BOOST_PP_INTERCEPT) ); | |
651 | ||
652 | // RP_GLOB_OPAQUE | |
653 | // | |
654 | // non-templated version for opaque rule parsers. | |
655 | # define BOOST_SPIRIT_RP_GLOB_OPAQUE(name,name_t,np,pars) \ | |
656 | static name_t const name = name_t () ; | |
657 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
658 | // PP_EMIT operations (fragment emittion based on array input) | |
659 | ||
660 | // - - Namespace handling | |
661 | ||
662 | // NS_OPEN | |
663 | # define BOOST_SPIRIT_RP__NS_OPEN(r,data,i,elem) \ | |
664 | namespace BOOST_SPIRIT_RP_OPTIONAL(elem) { | |
665 | ||
666 | // NS_QUALIFY | |
667 | # define BOOST_SPIRIT_RP__NS_QUALIFY(r,data,i,elem) \ | |
668 | BOOST_SPIRIT_RP_OPTIONAL(elem ::) | |
669 | ||
670 | // NS_CLOSE | |
671 | # define BOOST_SPIRIT_RP__NS_CLOSE(r,data,i,elem) } | |
672 | ||
673 | // - - Parameter handling | |
674 | ||
675 | // PM_STATIC | |
676 | # define BOOST_SPIRIT_RP__PM_STATIC(r,data,i,elem) \ | |
677 | static typename ::boost::call_traits< data ## i >::reference elem ; | |
678 | ||
679 | // PM_CTOR_PARAMS | |
680 | # define BOOST_SPIRIT_RP__PM_CTOR_PARAMS(r,data,i,elem) \ | |
681 | BOOST_PP_COMMA_IF(i) \ | |
682 | typename ::boost::call_traits< data ## i >::param_type elem | |
683 | ||
684 | // PM_CTOR_ARGS | |
685 | # define BOOST_SPIRIT_RP__PM_CTOR_ARGS(r,data,i,elem) \ | |
686 | BOOST_PP_COMMA_IF(i) elem | |
687 | ||
688 | // PM_CTOR_INIT_LIST | |
689 | # define BOOST_SPIRIT_RP__PM_CTOR_INIT_LIST(r,data,i,elem) \ | |
690 | BOOST_PP_COMMA_IF(i) __p ## i ( elem ) | |
691 | ||
692 | // PM_CTOR_COPY_INIT_LIST | |
693 | # define BOOST_SPIRIT_RP__PM_CTOR_COPY_INIT_LIST(r,data,i,elem) \ | |
694 | BOOST_PP_COMMA_IF(i) __p ## i ( that. __p ## i ) | |
695 | ||
696 | ||
697 | // PM_TEMPLATE_PARAMS | |
698 | # define BOOST_SPIRIT_RP__PM_TEMPLATE_PARAMS(r,data,i,elem) , data ## i | |
699 | ||
700 | // - strictly typed parameters of the opaque rule_parser | |
701 | ||
702 | // PM_OPAQUE_STATIC | |
703 | # define BOOST_SPIRIT_RP__PM_OPAQUE_STATIC(r,data,i,elem) \ | |
704 | static ::boost::call_traits< \ | |
705 | BOOST_SPIRIT_RP_TYPE(BOOST_PP_TUPLE_ELEM(2,0,elem)) \ | |
706 | >::reference BOOST_PP_TUPLE_ELEM(2,1,elem) ; | |
707 | ||
708 | // PM_OPAQUE_CTOR_PARAMS | |
709 | # define BOOST_SPIRIT_RP__PM_OPAQUE_CTOR_PARAMS(r,data,i,elem) \ | |
710 | BOOST_PP_COMMA_IF(i) ::boost::call_traits< \ | |
711 | BOOST_SPIRIT_RP_TYPE(BOOST_PP_TUPLE_ELEM(2,0,elem)) \ | |
712 | >::param_type BOOST_PP_TUPLE_ELEM(2,1,elem) | |
713 | ||
714 | // PM_OPAQUE_GEN_PARAMS | |
715 | # define BOOST_SPIRIT_RP__PM_OPAQUE_GEN_PARAMS(r,data,i,elem) \ | |
716 | BOOST_PP_COMMA_IF(i) ::boost::call_traits< \ | |
717 | BOOST_SPIRIT_RP_TYPE(BOOST_PP_TUPLE_ELEM(2,0,elem)) \ | |
718 | >::param_type data ## i | |
719 | ||
720 | // - - Member variable handling | |
721 | ||
722 | // MV_NONSTATIC | |
723 | # define BOOST_SPIRIT_RP__MV_NONSTATIC(r,data,i,elem) \ | |
724 | data() BOOST_SPIRIT_RP_TYPE(BOOST_PP_TUPLE_ELEM(3,0,elem)) \ | |
725 | BOOST_PP_TUPLE_ELEM(3,1,elem) ; | |
726 | ||
727 | // MV_STATIC | |
728 | # define BOOST_SPIRIT_RP__MV_STATIC(r,data,i,elem) \ | |
729 | static data() ::boost::call_traits< \ | |
730 | data() BOOST_SPIRIT_RP_TYPE(BOOST_PP_TUPLE_ELEM(3,0,elem)) \ | |
731 | >::reference BOOST_PP_TUPLE_ELEM(3,1,elem) ; | |
732 | ||
733 | // MV_CTOR_INIT_LIST | |
734 | # define BOOST_SPIRIT_RP__MV_CTOR_INIT_LIST(r,data,i,elem) \ | |
735 | BOOST_PP_COMMA_IF(i) \ | |
736 | BOOST_PP_TUPLE_ELEM(3,1,elem) BOOST_PP_TUPLE_ELEM(3,2,elem) | |
737 | ||
738 | // MV_CTOR_COPY_INIT_LIST | |
739 | # define BOOST_SPIRIT_RP__MV_CTOR_COPY_INIT_LIST(r,data,i,elem) \ | |
740 | BOOST_PP_COMMA_IF(i) \ | |
741 | BOOST_PP_TUPLE_ELEM(3,1,elem) (data . BOOST_PP_TUPLE_ELEM(3,1,elem)) | |
742 | ||
743 | // - - Action placeholder handling | |
744 | ||
745 | // AP_STATIC | |
746 | # define BOOST_SPIRIT_RP__AP_STATIC(r,data,i,elem) static __A ## i & elem ; | |
747 | ||
748 | // AP_CTOR_PARAMS | |
749 | # define BOOST_SPIRIT_RP__AP_CTOR_PARAMS(r,data,i,elem) \ | |
750 | BOOST_SPIRIT_RP_COMMA_IF_OR(data,i) \ | |
751 | typename ::boost::call_traits< __A ## i >::param_type elem | |
752 | ||
753 | // AP_CTOR_ARGS | |
754 | # define BOOST_SPIRIT_RP__AP_CTOR_ARGS(r,data,i,elem) \ | |
755 | BOOST_SPIRIT_RP_COMMA_IF_OR(data,i) elem | |
756 | ||
757 | // AP_CTOR_INIT_LIST | |
758 | # define BOOST_SPIRIT_RP__AP_CTOR_INIT_LIST(r,data,i,elem) \ | |
759 | BOOST_SPIRIT_RP_COMMA_IF_OR(data,i) __a ## i ( elem ) | |
760 | ||
761 | // AP_CTOR_COPY_INIT_LIST | |
762 | # define BOOST_SPIRIT_RP__AP_CTOR_COPY_INIT_LIST(r,data,i,elem) \ | |
763 | BOOST_SPIRIT_RP_COMMA_IF_OR(data,i) __a ## i ( that. __a ## i ) | |
764 | ||
765 | // AP_TEMPLATE_PARAMS | |
766 | # define BOOST_SPIRIT_RP__AP_TEMPLATE_PARAMS(r,data,i,elem) \ | |
767 | , BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2,0,data),i) \ | |
768 | BOOST_PP_EXPR_IIF(BOOST_PP_TUPLE_ELEM(2,1,data), \ | |
769 | = ::BOOST_SPIRIT_CLASSIC_NS::type_of::nop_functor) | |
770 | ||
771 | // AP_REBOUND_ARGS | |
772 | # define BOOST_SPIRIT_RP__AP_REBOUND_ARGS(r,data,i,elem) \ | |
773 | BOOST_PP_COMMA_IF(i) \ | |
774 | ::BOOST_SPIRIT_CLASSIC_NS::type_of::get_placeholdee< __action_placeholder:: elem > \ | |
775 | ( __a ## i , data ) | |
776 | ||
777 | // AP_REBOUND_TPL_ARGS | |
778 | # define BOOST_SPIRIT_RP__AP_REBOUND_TPL_ARGS(r,data,i,elem) \ | |
779 | , typename ::BOOST_SPIRIT_CLASSIC_NS::type_of::placeholdee< \ | |
780 | __action_placeholder:: elem , __A ## i, data >::type | |
781 | ||
782 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
783 | // PP_EMIT | |
784 | // | |
785 | // Performs one of the operations in the above section on an optional array. | |
786 | // | |
787 | # define BOOST_SPIRIT_RP_EMIT(op, array, data) \ | |
788 | BOOST_SPIRIT_RP_ARRAY_FOR_EACH_I(BOOST_SPIRIT_RP__ ## op,data,array) | |
789 | // --- --- - - --- - - --- - - - - --- - - - - - - - - - - - - - - - - - - - - - | |
790 | // RP_ARRAY_FOR_EACH_I | |
791 | // | |
792 | // Iterates an optional array. That is you can pass e.g.'-' or 'none' to denote | |
793 | // emptiness. | |
794 | # define BOOST_SPIRIT_RP_ARRAY_FOR_EACH_I(macro,data,optional_array) \ | |
795 | BOOST_PP_IIF(BOOST_PP_IS_BINARY(optional_array), \ | |
796 | BOOST_SPIRIT_RP_ARRAY_FOR_EACH_I_IMPL, \ | |
797 | BOOST_PP_TUPLE_EAT(3))(macro,data,optional_array) | |
798 | ||
799 | // RP_ARRAY_FOR_EACH_I_IMPL | |
800 | # define BOOST_SPIRIT_RP_ARRAY_FOR_EACH_I_IMPL(macro,data,array) \ | |
801 | BOOST_SPIRIT_RP_IF(BOOST_PP_ARRAY_SIZE(array),PP_SEQ_FOR_EACH_I,3) \ | |
802 | (macro,data, BOOST_SPIRIT_RP_IF(BOOST_PP_ARRAY_SIZE(array), \ | |
803 | PP_TUPLE_TO_SEQ,2) array) | |
804 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
805 | // RP_ARRAY_SIZE | |
806 | // | |
807 | // Expands to the size of an "optional array". | |
808 | // | |
809 | // Examples: | |
810 | // | |
811 | // BOOST_SPIRIT_RP_ARRAY_SIZE( (2,(a,b)) ) // 2 | |
812 | // BOOST_SPIRIT_RP_ARRAY_SIZE( (0,()) ) // 0 | |
813 | // BOOST_SPIRIT_RP_ARRAY_SIZE( none ) // 0 | |
814 | // BOOST_SPIRIT_RP_ARRAY_SIZE( - ) // 0 | |
815 | // | |
816 | # define BOOST_SPIRIT_RP_ARRAY_SIZE(optional_array) \ | |
817 | BOOST_PP_IIF(BOOST_PP_IS_BINARY(optional_array), \ | |
818 | BOOST_PP_ARRAY_SIZE, 0 BOOST_PP_TUPLE_EAT(1))(optional_array) | |
819 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
820 | // RP_OPTIONAL | |
821 | // | |
822 | // Expands to nothing if the argument is parenthesized. | |
823 | // | |
824 | // Examples: | |
825 | // | |
826 | // BOOST_SPIRIT_RP_OPTIONAL( foobar ) // foobar | |
827 | // BOOST_SPIRIT_RP_OPTIONAL( (none) ) // evaluates to nothing | |
828 | // | |
829 | # define BOOST_SPIRIT_RP_OPTIONAL(elem) \ | |
830 | BOOST_PP_EXPR_IIF(BOOST_PP_COMPL(BOOST_PP_IS_UNARY(elem)),elem) | |
831 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
832 | // RP_COMMA_IF_OR | |
833 | // | |
834 | // Expands to nothing if both arguments are zero, otherwise expands to a comma. | |
835 | // | |
836 | # define BOOST_SPIRIT_RP_COMMA_IF_OR(a,b) \ | |
837 | BOOST_PP_IIF(BOOST_PP_OR(a,b),BOOST_PP_COMMA,BOOST_PP_EMPTY)() | |
838 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
839 | // RP_IF | |
840 | // | |
841 | // BOOST_SPIRIT_RP_IF(cond,name,arity) | |
842 | // | |
843 | // is equivalent to: | |
844 | // | |
845 | // BOOST_PP_IF(cond,BOOST_name,BOOST_PP_TUPLE_EAT(arity)) | |
846 | // | |
847 | # define BOOST_SPIRIT_RP_IF(cond,name,arity) \ | |
848 | BOOST_PP_IF(cond,BOOST_ ## name,BOOST_PP_TUPLE_EAT(arity)) | |
849 | ||
850 | //------------------------------------------------------------------------------ | |
851 | // Wrapper and gernator function to embed a parser by reference | |
852 | //------------------------------------------------------------------------------ | |
853 | ||
854 | namespace boost { namespace spirit { | |
855 | ||
856 | BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN | |
857 | ||
858 | // Wrapper to embed a parser by reference | |
859 | ||
860 | template<class P> class parser_reference | |
861 | : public parser< parser_reference<P> > | |
862 | { | |
863 | P const & ref_that; | |
864 | public: | |
865 | parser_reference(P & that) | |
866 | // we allow implicit conversion but forbid temporaries. | |
867 | : ref_that(that) | |
868 | { } | |
869 | ||
870 | typedef parser_reference<P> self_t; | |
871 | typedef self_t const & embed_t; | |
872 | typedef typename P::parser_category_t parser_category_t; | |
873 | ||
874 | template<typename ScannerT> struct result | |
875 | { typedef typename P::BOOST_NESTED_TEMPLATE result<ScannerT>::type type; }; | |
876 | ||
877 | template<typename ScannerT> | |
878 | typename result<ScannerT>::type | |
879 | parse(ScannerT const & scan) const | |
880 | { return this->ref_that.parse(scan); } | |
881 | }; | |
882 | ||
883 | template<class P> parser_reference<P> | |
884 | embed_by_reference(::BOOST_SPIRIT_CLASSIC_NS::parser<P> & p) | |
885 | { return p; } | |
886 | ||
887 | BOOST_SPIRIT_CLASSIC_NAMESPACE_END | |
888 | ||
889 | } } // namespace ::BOOST_SPIRIT_CLASSIC_NS | |
890 | ||
891 | BOOST_TYPEOF_REGISTER_TEMPLATE(BOOST_SPIRIT_CLASSIC_NS::parser_reference, 1) | |
892 | ||
893 | //------------------------------------------------------------------------------ | |
894 | // Expression templates for action placeholders. | |
895 | //------------------------------------------------------------------------------ | |
896 | ||
897 | namespace boost { namespace spirit { | |
898 | ||
899 | BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN | |
900 | ||
901 | namespace type_of { | |
902 | ||
903 | // No-operation functor | |
904 | ||
905 | struct nop_functor | |
906 | { | |
907 | template<typename T> | |
908 | bool operator()(T const &) const | |
909 | { return false; } | |
910 | template<typename T, typename U> | |
911 | bool operator()(T const &, U const &) const | |
912 | { return false; } | |
913 | ||
914 | typedef bool result_type; | |
915 | }; | |
916 | ||
917 | // Composite action | |
918 | ||
919 | template<typename Action1, typename Action2> | |
920 | class composite_action | |
921 | { | |
922 | Action1 fnc_a1; | |
923 | Action2 fnc_a2; | |
924 | public: | |
925 | composite_action(Action1 const & a1, Action2 const & a2) | |
926 | : fnc_a1(a1), fnc_a2(a2) | |
927 | { } | |
928 | ||
929 | template<typename T> | |
930 | void operator()(T const & inp) const | |
931 | { fnc_a1(inp); fnc_a2(inp); } | |
932 | ||
933 | template<typename T, typename U> | |
934 | void operator()(T const & inp1, U const inp2) const | |
935 | { fnc_a1(inp1, inp2); fnc_a2(inp1, inp2); } | |
936 | }; | |
937 | ||
938 | // Action concatenation (and optimize away nop_functorS) | |
939 | ||
940 | template<typename Action1, typename Action2> | |
941 | struct action_concatenator | |
942 | { | |
943 | typedef composite_action<Action1,Action2> type; | |
944 | ||
945 | static type concatenate(Action1 const & a1, Action2 const & a2) | |
946 | { return composite_action<Action1,Action2>(a1,a2); } | |
947 | }; | |
948 | template<typename Action> struct action_concatenator<nop_functor, Action> | |
949 | { | |
950 | typedef Action type; | |
951 | ||
952 | static type concatenate(nop_functor const &, Action const & a) | |
953 | { return a; } | |
954 | }; | |
955 | template<typename Action> struct action_concatenator<Action, nop_functor> | |
956 | { | |
957 | typedef Action type; | |
958 | ||
959 | static type concatenate(Action const & a, nop_functor const &) | |
960 | { return a; } | |
961 | }; | |
962 | template<> struct action_concatenator<nop_functor, nop_functor> | |
963 | { | |
964 | typedef nop_functor type; | |
965 | ||
966 | static type concatenate(nop_functor const &, nop_functor const &) | |
967 | { return nop_functor(); } | |
968 | }; | |
969 | ||
970 | template<typename Action1, typename Action2> | |
971 | typename action_concatenator<Action1,Action2>::type | |
972 | concatenate_actions(Action1 const & a1, Action2 const & a2) | |
973 | { | |
974 | return action_concatenator<Action1,Action2>::concatenate(a1,a2); | |
975 | } | |
976 | ||
977 | // Action chains | |
978 | ||
979 | enum action_chain_mode { replace, append }; | |
980 | ||
981 | template<class Placeholder, action_chain_mode Mode, typename Action> | |
982 | class action_chain | |
983 | { | |
984 | Action fnc_action; | |
985 | public: | |
986 | action_chain(Action const & a) | |
987 | : fnc_action(a) | |
988 | { } | |
989 | ||
990 | typedef Action action_type; | |
991 | ||
992 | Action const & action() const { return fnc_action; } | |
993 | }; | |
994 | ||
995 | // This operator adds actions to an action chain definition | |
996 | template<class PH, action_chain_mode M, typename A1, typename A2> | |
997 | action_chain<PH, M, typename action_concatenator<A1,A2>::type> | |
998 | operator, (action_chain<PH,M,A1> const & chain, A2 const & a) | |
999 | { | |
1000 | return action_chain<PH,M,typename action_concatenator<A1,A2>::type> | |
1001 | ( concatenate_actions(chain.action(), a) ); | |
1002 | } | |
1003 | ||
1004 | // Expression template for mutiple action chain assignments | |
1005 | template<class ChainOrChains, class LastChain> | |
1006 | class action_chains | |
1007 | { | |
1008 | ChainOrChains obj_head; | |
1009 | LastChain obj_tail; | |
1010 | public: | |
1011 | action_chains(ChainOrChains const & head, LastChain const & tail) | |
1012 | : obj_head(head), obj_tail(tail) | |
1013 | { } | |
1014 | ||
1015 | typedef ChainOrChains head_type; | |
1016 | typedef LastChain tail_type; | |
1017 | ||
1018 | head_type const & head() const { return obj_head; } | |
1019 | tail_type const & tail() const { return obj_tail; } | |
1020 | }; | |
1021 | ||
1022 | // Action chain concatenation | |
1023 | template<class Head, class Tail> | |
1024 | action_chains<Head,Tail> make_chain(Head const & h, Tail const & t) | |
1025 | { return action_chains<Head,Tail>(h,t); } | |
1026 | ||
1027 | template<class PH1, action_chain_mode M1, typename A1, | |
1028 | class PH2, action_chain_mode M2, typename A2> | |
1029 | action_chains< action_chain<PH1,M1,A1>, action_chain<PH2,M2,A2> > | |
1030 | operator, (action_chain<PH1,M1,A1> const & h, | |
1031 | action_chain<PH2,M2,A2> const & t) | |
1032 | { return make_chain(h,t); } | |
1033 | ||
1034 | template<class Head, class Tail,class PH, action_chain_mode M, typename A> | |
1035 | action_chains< action_chains<Head,Tail>, action_chain<PH,M,A> > | |
1036 | operator, (action_chains<Head,Tail> const & h, action_chain<PH,M,A> const & t) | |
1037 | { return make_chain(h,t); } | |
1038 | ||
1039 | ||
1040 | // Extract the (maybe composite) action associated with an action | |
1041 | // placeholders from the chains with a fold algorithm. | |
1042 | template<class Placeholder, typename StartAction, class NewChainOrChains> | |
1043 | struct placeholdee | |
1044 | { | |
1045 | typedef StartAction type; | |
1046 | ||
1047 | static type get(StartAction const & a, NewChainOrChains const &) | |
1048 | { return a; } | |
1049 | }; | |
1050 | ||
1051 | template<class Placeholder, // <-- non-deduced | |
1052 | typename StartAction, class NewChainOrChains> | |
1053 | typename placeholdee<Placeholder,StartAction,NewChainOrChains>::type | |
1054 | get_placeholdee(StartAction const & a, NewChainOrChains const & c) | |
1055 | { return placeholdee<Placeholder,StartAction,NewChainOrChains>::get(a,c); } | |
1056 | ||
1057 | template<class Placeholder, typename StartAction, class Head, class Tail> | |
1058 | struct placeholdee | |
1059 | < Placeholder, StartAction, action_chains<Head,Tail> > | |
1060 | { | |
1061 | typedef typename placeholdee<Placeholder, | |
1062 | typename placeholdee<Placeholder,StartAction,Head>::type, Tail >::type | |
1063 | type; | |
1064 | ||
1065 | static type get(StartAction const & a, action_chains<Head,Tail> const & c) | |
1066 | { | |
1067 | return get_placeholdee<Placeholder>( | |
1068 | get_placeholdee<Placeholder>(a,c.head()), c.tail() ); | |
1069 | } | |
1070 | }; | |
1071 | ||
1072 | template<class Placeholder, typename StartAction, typename A> | |
1073 | struct placeholdee | |
1074 | < Placeholder, StartAction, action_chain<Placeholder,replace,A> > | |
1075 | { | |
1076 | typedef A type; | |
1077 | ||
1078 | static type get(StartAction const &, | |
1079 | action_chain<Placeholder,replace,A> const & c) | |
1080 | { return c.action(); } | |
1081 | }; | |
1082 | ||
1083 | template<class Placeholder, typename StartAction, typename A> | |
1084 | struct placeholdee | |
1085 | < Placeholder, StartAction, action_chain<Placeholder,append,A> > | |
1086 | { | |
1087 | typedef typename action_concatenator<StartAction,A>::type type; | |
1088 | ||
1089 | static type get(StartAction const & a, | |
1090 | action_chain<Placeholder,append,A> const & c) | |
1091 | { return concatenate_actions(a,c.action()); } | |
1092 | }; | |
1093 | ||
1094 | } | |
1095 | ||
1096 | BOOST_SPIRIT_CLASSIC_NAMESPACE_END | |
1097 | ||
1098 | } } // namespace ::BOOST_SPIRIT_CLASSIC_NS::type_of | |
1099 | ||
1100 | BOOST_TYPEOF_REGISTER_TYPE(BOOST_SPIRIT_CLASSIC_NS::type_of::nop_functor) | |
1101 | BOOST_TYPEOF_REGISTER_TEMPLATE(BOOST_SPIRIT_CLASSIC_NS::type_of::composite_action,2) | |
1102 | ||
1103 | //------------------------------------------------------------------------------ | |
1104 | // Misc.utilities | |
1105 | //------------------------------------------------------------------------------ | |
1106 | ||
1107 | namespace boost { namespace spirit { | |
1108 | ||
1109 | BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN | |
1110 | ||
1111 | namespace type_of { | |
1112 | ||
1113 | // Utility function to create a dependency to a template argument. | |
1114 | ||
1115 | template<typename T, typename X> | |
1116 | X const & depend_on_type(X const & x) | |
1117 | { return x; } | |
1118 | ||
1119 | // Utility to allow use parenthesized type expressions with commas inside | |
1120 | // as a type within macros. Thanks to Dave Abrahams for telling me this nice | |
1121 | // trick. | |
1122 | ||
1123 | #define BOOST_SPIRIT_RP_TYPE(x) \ | |
1124 | ::BOOST_SPIRIT_CLASSIC_NS::type_of::remove_special_fptr \ | |
1125 | < ::BOOST_SPIRIT_CLASSIC_NS::type_of::special_result & (*) x >::type | |
1126 | ||
1127 | struct special_result; | |
1128 | ||
1129 | template<typename T> struct remove_special_fptr { }; | |
1130 | template<typename T> struct remove_special_fptr< special_result & (*)(T) > | |
1131 | { typedef T type; }; | |
1132 | ||
1133 | } | |
1134 | ||
1135 | BOOST_SPIRIT_CLASSIC_NAMESPACE_END | |
1136 | ||
1137 | } } // namespace ::BOOST_SPIRIT_CLASSIC_NS::type_of | |
1138 | ||
1139 | //------------------------------------------------------------------------------ | |
1140 | #endif | |
1141 | //------------------------------------------------------------------------------ | |
1142 |