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 multiple 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: parser_reference(P & that)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 parse(ScannerT const & scan) const879 parse(ScannerT const & scan) const 880 { return this->ref_that.parse(scan); } 881 }; 882 883 template<class P> parser_reference<P> embed_by_reference(::BOOST_SPIRIT_CLASSIC_NS::parser<P> & 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> operator ()boost::spirit::type_of::nop_functor908 bool operator()(T const &) const 909 { return false; } 910 template<typename T, typename U> operator ()boost::spirit::type_of::nop_functor911 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: composite_action(Action1 const & a1,Action2 const & a2)925 composite_action(Action1 const & a1, Action2 const & a2) 926 : fnc_a1(a1), fnc_a2(a2) 927 { } 928 929 template<typename T> operator ()(T const & inp) const930 void operator()(T const & inp) const 931 { fnc_a1(inp); fnc_a2(inp); } 932 933 template<typename T, typename U> operator ()(T const & inp1,U const inp2) const934 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 concatenateboost::spirit::type_of::action_concatenator945 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 concatenateboost::spirit::type_of::action_concatenator952 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 concatenateboost::spirit::type_of::action_concatenator959 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 concatenateboost::spirit::type_of::action_concatenator966 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 concatenate_actions(Action1 const & a1,Action2 const & a2)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: action_chain(Action const & a)986 action_chain(Action const & a) 987 : fnc_action(a) 988 { } 989 990 typedef Action action_type; 991 action() const992 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> operator ,(action_chain<PH,M,A1> const & chain,A2 const & a)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 multiple action chain assignments 1005 template<class ChainOrChains, class LastChain> 1006 class action_chains 1007 { 1008 ChainOrChains obj_head; 1009 LastChain obj_tail; 1010 public: action_chains(ChainOrChains const & head,LastChain const & tail)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 head() const1018 head_type const & head() const { return obj_head; } tail() const1019 tail_type const & tail() const { return obj_tail; } 1020 }; 1021 1022 // Action chain concatenation 1023 template<class Head, class Tail> make_chain(Head const & h,Tail const & t)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> > operator ,(action_chain<PH1,M1,A1> const & h,action_chain<PH2,M2,A2> const & t)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> > operator ,(action_chains<Head,Tail> const & h,action_chain<PH,M,A> const & t)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 getboost::spirit::type_of::placeholdee1047 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 get_placeholdee(StartAction const & a,NewChainOrChains const & c)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 getboost::spirit::type_of::placeholdee1065 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 getboost::spirit::type_of::placeholdee1078 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 getboost::spirit::type_of::placeholdee1089 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> depend_on_type(X const & 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 1143