1 /*============================================================================= 2 Copyright (c) 2011-2012 Thomas Bernard 3 4 Distributed under the Boost Software License, Version 1.0. (See accompanying 5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 =============================================================================*/ 7 #ifndef BOOST_SPIRIT_REPOSITORY_QI_OPERATOR_DETAIL_KEYWORDS_HPP 8 #define BOOST_SPIRIT_REPOSITORY_QI_OPERATOR_DETAIL_KEYWORDS_HPP 9 10 #if defined(_MSC_VER) 11 #pragma once 12 #endif 13 #include <boost/spirit/repository/home/qi/directive/kwd.hpp> // for skipper_keyword_marker 14 #include <boost/spirit/home/qi/string/lit.hpp> 15 #include <boost/fusion/include/at.hpp> 16 #include <boost/fusion/include/any.hpp> 17 18 namespace boost { namespace spirit { namespace repository { namespace qi { namespace detail { 19 // Variant visitor class which handles dispatching the parsing to the selected parser 20 // This also handles passing the correct attributes and flags/counters to the subject parsers 21 template<typename T> 22 struct is_distinct : T::distinct { }; 23 24 template<typename T, typename Action> 25 struct is_distinct< spirit::qi::action<T,Action> > : T::distinct { }; 26 27 template<typename T> 28 struct is_distinct< spirit::qi::hold_directive<T> > : T::distinct { }; 29 30 31 32 template < typename Elements, typename Iterator ,typename Context ,typename Skipper 33 ,typename Flags ,typename Counters ,typename Attribute, typename NoCasePass> 34 struct parse_dispatcher 35 : public boost::static_visitor<bool> 36 { 37 38 typedef Iterator iterator_type; 39 typedef Context context_type; 40 typedef Skipper skipper_type; 41 typedef Elements elements_type; 42 43 typedef typename add_reference<Attribute>::type attr_reference; 44 public: parse_dispatcherboost::spirit::repository::qi::detail::parse_dispatcher45 parse_dispatcher(const Elements &elements,Iterator& first, Iterator const& last 46 , Context& context, Skipper const& skipper 47 , Flags &flags, Counters &counters, attr_reference attr) : 48 elements(elements), first(first), last(last) 49 , context(context), skipper(skipper) 50 , flags(flags),counters(counters), attr(attr) 51 {} 52 operator ()boost::spirit::repository::qi::detail::parse_dispatcher53 template<typename T> bool operator()(T& idx) const 54 { 55 return call(idx,typename traits::not_is_unused<Attribute>::type()); 56 } 57 58 template <typename Subject,typename Index> call_subject_unusedboost::spirit::repository::qi::detail::parse_dispatcher59 bool call_subject_unused( 60 Subject const &subject, Iterator &first, Iterator const &last 61 , Context& context, Skipper const& skipper 62 , Index& /*idx*/ ) const 63 { 64 Iterator save = first; 65 skipper_keyword_marker<Skipper,NoCasePass> 66 marked_skipper(skipper,flags[Index::value],counters[Index::value]); 67 68 if(subject.parse(first,last,context,marked_skipper,unused)) 69 { 70 return true; 71 } 72 first = save; 73 return false; 74 } 75 76 77 template <typename Subject,typename Index> call_subjectboost::spirit::repository::qi::detail::parse_dispatcher78 bool call_subject( 79 Subject const &subject, Iterator &first, Iterator const &last 80 , Context& context, Skipper const& skipper 81 , Index& /*idx*/ ) const 82 { 83 84 Iterator save = first; 85 skipper_keyword_marker<Skipper,NoCasePass> 86 marked_skipper(skipper,flags[Index::value],counters[Index::value]); 87 typename fusion::result_of::at_c<typename remove_reference<Attribute>::type, Index::value>::type 88 attr_ = fusion::at_c<Index::value>(attr); 89 if(subject.parse(first,last,context,marked_skipper,attr_)) 90 { 91 return true; 92 } 93 first = save; 94 return false; 95 } 96 97 #if defined(_MSC_VER) 98 # pragma warning(push) 99 # pragma warning(disable: 4127) // conditional expression is constant 100 #endif 101 // Handle unused attributes callboost::spirit::repository::qi::detail::parse_dispatcher102 template <typename T> bool call(T &idx, mpl::false_) const{ 103 104 typedef typename mpl::at<Elements,T>::type ElementType; 105 if( 106 (!is_distinct<ElementType>::value) 107 || skipper.parse(first,last,unused,unused,unused) 108 ){ 109 spirit::qi::skip_over(first, last, skipper); 110 return call_subject_unused(fusion::at_c<T::value>(elements), first, last, context, skipper, idx ); 111 } 112 return false; 113 } 114 // Handle normal attributes callboost::spirit::repository::qi::detail::parse_dispatcher115 template <typename T> bool call(T &idx, mpl::true_) const{ 116 typedef typename mpl::at<Elements,T>::type ElementType; 117 if( 118 (!is_distinct<ElementType>::value) 119 || skipper.parse(first,last,unused,unused,unused) 120 ){ 121 return call_subject(fusion::at_c<T::value>(elements), first, last, context, skipper, idx); 122 } 123 return false; 124 } 125 #if defined(_MSC_VER) 126 # pragma warning(pop) 127 #endif 128 129 const Elements &elements; 130 Iterator &first; 131 const Iterator &last; 132 Context & context; 133 const Skipper &skipper; 134 Flags &flags; 135 Counters &counters; 136 attr_reference attr; 137 }; 138 // string keyword loop handler 139 template <typename Elements, typename StringKeywords, typename IndexList, typename FlagsType, typename Modifiers> 140 struct string_keywords 141 { 142 // Create a variant type to be able to store parser indexes in the embedded symbols parser 143 typedef typename 144 spirit::detail::as_variant< 145 IndexList >::type parser_index_type; 146 147 /////////////////////////////////////////////////////////////////////////// 148 // build_char_type_sequence 149 // 150 // Build a fusion sequence from the kwd directive specified character type. 151 /////////////////////////////////////////////////////////////////////////// 152 template <typename Sequence > 153 struct build_char_type_sequence 154 { 155 struct element_char_type 156 { 157 template <typename T> 158 struct result; 159 160 template <typename F, typename Element> 161 struct result<F(Element)> 162 { 163 typedef typename Element::char_type type; 164 165 }; 166 template <typename F, typename Element,typename Action> 167 struct result<F(spirit::qi::action<Element,Action>) > 168 { 169 typedef typename Element::char_type type; 170 }; 171 template <typename F, typename Element> 172 struct result<F(spirit::qi::hold_directive<Element>)> 173 { 174 typedef typename Element::char_type type; 175 }; 176 177 // never called, but needed for decltype-based result_of (C++0x) 178 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES 179 template <typename Element> 180 typename result<element_char_type(Element)>::type 181 operator()(Element&&) const; 182 #endif 183 }; 184 185 // Compute the list of character types of the child kwd directives 186 typedef typename 187 fusion::result_of::transform<Sequence, element_char_type>::type 188 type; 189 }; 190 191 192 /////////////////////////////////////////////////////////////////////////// 193 // get_keyword_char_type 194 // 195 // Collapses the character type coming from the subject kwd parsers and 196 // and checks that they are all identical (necessary in order to be able 197 // to build a tst parser to parse the keywords. 198 /////////////////////////////////////////////////////////////////////////// 199 template <typename Sequence> 200 struct get_keyword_char_type 201 { 202 // Make sure each of the types occur only once in the type list 203 typedef typename 204 mpl::fold< 205 Sequence, mpl::vector<>, 206 mpl::if_< 207 mpl::contains<mpl::_1, mpl::_2>, 208 mpl::_1, mpl::push_back<mpl::_1, mpl::_2> 209 > 210 >::type 211 no_duplicate_char_types; 212 213 // If the compiler traps here this means you mixed 214 // character type for the keywords specified in the 215 // kwd directive sequence. 216 BOOST_MPL_ASSERT_RELATION( mpl::size<no_duplicate_char_types>::value, ==, 1 ); 217 218 typedef typename mpl::front<no_duplicate_char_types>::type type; 219 220 }; 221 222 // Get the character type for the tst parser 223 typedef typename build_char_type_sequence< StringKeywords >::type char_types; 224 typedef typename get_keyword_char_type< 225 typename mpl::if_< 226 mpl::equal_to< 227 typename mpl::size < char_types >::type 228 , mpl::int_<0> 229 > 230 , mpl::vector< boost::spirit::standard::char_type > 231 , char_types >::type 232 >::type char_type; 233 234 // Our symbols container 235 typedef spirit::qi::tst< char_type, parser_index_type> keywords_type; 236 237 // Filter functor used for case insensitive parsing 238 template <typename CharEncoding> 239 struct no_case_filter 240 { operator ()boost::spirit::repository::qi::detail::string_keywords::no_case_filter241 char_type operator()(char_type ch) const 242 { 243 return static_cast<char_type>(CharEncoding::tolower(ch)); 244 } 245 }; 246 247 /////////////////////////////////////////////////////////////////////////// 248 // build_case_type_sequence 249 // 250 // Build a fusion sequence from the kwd/ikwd directives 251 // in order to determine if case sensitive and case insensitive 252 // keywords have been mixed. 253 /////////////////////////////////////////////////////////////////////////// 254 template <typename Sequence > 255 struct build_case_type_sequence 256 { 257 struct element_case_type 258 { 259 template <typename T> 260 struct result; 261 262 template <typename F, typename Element> 263 struct result<F(Element)> 264 { 265 typedef typename Element::no_case_keyword type; 266 267 }; 268 template <typename F, typename Element,typename Action> 269 struct result<F(spirit::qi::action<Element,Action>) > 270 { 271 typedef typename Element::no_case_keyword type; 272 }; 273 template <typename F, typename Element> 274 struct result<F(spirit::qi::hold_directive<Element>)> 275 { 276 typedef typename Element::no_case_keyword type; 277 }; 278 279 // never called, but needed for decltype-based result_of (C++0x) 280 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES 281 template <typename Element> 282 typename result<element_case_type(Element)>::type 283 operator()(Element&&) const; 284 #endif 285 }; 286 287 // Compute the list of character types of the child kwd directives 288 typedef typename 289 fusion::result_of::transform<Sequence, element_case_type>::type 290 type; 291 }; 292 293 /////////////////////////////////////////////////////////////////////////// 294 // get_nb_case_types 295 // 296 // Counts the number of entries in the case type sequence matching the 297 // CaseType parameter (mpl::true_ -> case insensitve 298 // , mpl::false_ -> case sensitive 299 /////////////////////////////////////////////////////////////////////////// 300 template <typename Sequence,typename CaseType> 301 struct get_nb_case_types 302 { 303 // Make sure each of the types occur only once in the type list 304 typedef typename 305 mpl::count_if< 306 Sequence, mpl::equal_to<mpl::_,CaseType> 307 >::type type; 308 309 310 }; 311 // Build the case type sequence 312 typedef typename build_case_type_sequence< StringKeywords >::type case_type_sequence; 313 // Count the number of case sensitive entries and case insensitve entries 314 typedef typename get_nb_case_types<case_type_sequence,mpl::true_>::type ikwd_count; 315 typedef typename get_nb_case_types<case_type_sequence,mpl::false_>::type kwd_count; 316 // Get the size of the original sequence 317 typedef typename mpl::size<IndexList>::type nb_elements; 318 // Determine if all the kwd directive are case sensitive/insensitive 319 typedef typename mpl::and_< 320 typename mpl::greater< nb_elements, mpl::int_<0> >::type 321 , typename mpl::equal_to< ikwd_count, nb_elements>::type 322 >::type all_ikwd; 323 324 typedef typename mpl::and_< 325 typename mpl::greater< nb_elements, mpl::int_<0> >::type 326 , typename mpl::equal_to< kwd_count, nb_elements>::type 327 >::type all_kwd; 328 329 typedef typename mpl::or_< all_kwd, all_ikwd >::type all_directives_of_same_type; 330 331 // Do we have a no case modifier 332 typedef has_modifier<Modifiers, spirit::tag::char_code_base<spirit::tag::no_case> > no_case_modifier; 333 334 // Should the no_case filter always be used ? 335 typedef typename mpl::or_< 336 no_case_modifier, 337 mpl::and_< 338 all_directives_of_same_type 339 ,all_ikwd 340 > 341 >::type 342 no_case; 343 344 typedef no_case_filter< 345 typename spirit::detail::get_encoding_with_case< 346 Modifiers 347 , char_encoding::standard 348 , no_case::value>::type> 349 nc_filter; 350 // Determine the standard case filter type 351 typedef typename mpl::if_< 352 no_case 353 , nc_filter 354 , spirit::qi::tst_pass_through >::type 355 first_pass_filter_type; 356 357 typedef typename mpl::or_< 358 all_directives_of_same_type 359 , no_case_modifier 360 >::type requires_one_pass; 361 362 363 // Functor which adds all the keywords/subject parser indexes 364 // collected from the subject kwd directives to the keyword tst parser 365 struct keyword_entry_adder 366 { 367 typedef int result_type; 368 keyword_entry_adderboost::spirit::repository::qi::detail::string_keywords::keyword_entry_adder369 keyword_entry_adder(shared_ptr<keywords_type> lookup,FlagsType &flags, Elements &elements) : 370 lookup(lookup) 371 ,flags(flags) 372 ,elements(elements) 373 {} 374 375 template <typename T> operator ()boost::spirit::repository::qi::detail::string_keywords::keyword_entry_adder376 int operator()(const T &index) const 377 { 378 return call(fusion::at_c<T::value>(elements),index); 379 } 380 381 template <typename T, typename Position, typename Action> callboost::spirit::repository::qi::detail::string_keywords::keyword_entry_adder382 int call(const spirit::qi::action<T,Action> &parser, const Position position ) const 383 { 384 385 // Make the keyword/parse index entry in the tst parser 386 lookup->add( 387 traits::get_begin<char_type>(get_string(parser.subject.keyword)), 388 traits::get_end<char_type>(get_string(parser.subject.keyword)), 389 position 390 ); 391 // Get the initial state of the flags array and store it in the flags initializer 392 flags[Position::value]=parser.subject.iter.flag_init(); 393 return 0; 394 } 395 396 template <typename T, typename Position> callboost::spirit::repository::qi::detail::string_keywords::keyword_entry_adder397 int call( const T & parser, const Position position) const 398 { 399 // Make the keyword/parse index entry in the tst parser 400 lookup->add( 401 traits::get_begin<char_type>(get_string(parser.keyword)), 402 traits::get_end<char_type>(get_string(parser.keyword)), 403 position 404 ); 405 // Get the initial state of the flags array and store it in the flags initializer 406 flags[Position::value]=parser.iter.flag_init(); 407 return 0; 408 } 409 410 template <typename T, typename Position> callboost::spirit::repository::qi::detail::string_keywords::keyword_entry_adder411 int call( const spirit::qi::hold_directive<T> & parser, const Position position) const 412 { 413 // Make the keyword/parse index entry in the tst parser 414 lookup->add( 415 traits::get_begin<char_type>(get_string(parser.subject.keyword)), 416 traits::get_end<char_type>(get_string(parser.subject.keyword)), 417 position 418 ); 419 // Get the initial state of the flags array and store it in the flags initializer 420 flags[Position::value]=parser.subject.iter.flag_init(); 421 return 0; 422 } 423 424 425 template <typename String, bool no_attribute> get_stringboost::spirit::repository::qi::detail::string_keywords::keyword_entry_adder426 const String get_string(const boost::spirit::qi::literal_string<String,no_attribute> &parser) const 427 { 428 return parser.str; 429 } 430 431 template <typename String, bool no_attribute> 432 const typename boost::spirit::qi::no_case_literal_string<String,no_attribute>::string_type & get_stringboost::spirit::repository::qi::detail::string_keywords::keyword_entry_adder433 get_string(const boost::spirit::qi::no_case_literal_string<String,no_attribute> &parser) const 434 { 435 return parser.str_lo; 436 } 437 438 439 440 shared_ptr<keywords_type> lookup; 441 FlagsType & flags; 442 Elements &elements; 443 }; 444 string_keywordsboost::spirit::repository::qi::detail::string_keywords445 string_keywords(Elements &elements,FlagsType &flags_init) : lookup(new keywords_type()) 446 { 447 // Loop through all the subject parsers to build the keyword parser symbol parser 448 IndexList indexes; 449 keyword_entry_adder f1(lookup,flags_init,elements); 450 fusion::for_each(indexes,f1); 451 452 } 453 template <typename Iterator,typename ParseVisitor, typename Skipper> parseboost::spirit::repository::qi::detail::string_keywords454 bool parse( 455 Iterator &first, 456 const Iterator &last, 457 const ParseVisitor &parse_visitor, 458 const Skipper &/*skipper*/) const 459 { 460 if(parser_index_type* val_ptr = 461 lookup->find(first,last,first_pass_filter_type())) 462 { 463 if(!apply_visitor(parse_visitor,*val_ptr)){ 464 return false; 465 } 466 return true; 467 } 468 return false; 469 } 470 471 template <typename Iterator,typename ParseVisitor, typename NoCaseParseVisitor,typename Skipper> parseboost::spirit::repository::qi::detail::string_keywords472 bool parse( 473 Iterator &first, 474 const Iterator &last, 475 const ParseVisitor &parse_visitor, 476 const NoCaseParseVisitor &no_case_parse_visitor, 477 const Skipper &/*skipper*/) const 478 { 479 Iterator saved_first = first; 480 if(parser_index_type* val_ptr = 481 lookup->find(first,last,first_pass_filter_type())) 482 { 483 if(!apply_visitor(parse_visitor,*val_ptr)){ 484 return false; 485 } 486 return true; 487 } 488 // Second pass case insensitive 489 if(parser_index_type* val_ptr 490 = lookup->find(saved_first,last,nc_filter())) 491 { 492 first = saved_first; 493 if(!apply_visitor(no_case_parse_visitor,*val_ptr)){ 494 return false; 495 } 496 return true; 497 } 498 return false; 499 } 500 shared_ptr<keywords_type> lookup; 501 502 503 }; 504 505 struct empty_keywords_list 506 { 507 typedef mpl::true_ requires_one_pass; 508 empty_keywords_listboost::spirit::repository::qi::detail::empty_keywords_list509 empty_keywords_list() 510 {} 511 template<typename Elements> empty_keywords_listboost::spirit::repository::qi::detail::empty_keywords_list512 empty_keywords_list(const Elements &) 513 {} 514 515 template<typename Elements, typename FlagsInit> empty_keywords_listboost::spirit::repository::qi::detail::empty_keywords_list516 empty_keywords_list(const Elements &, const FlagsInit &) 517 {} 518 519 template <typename Iterator,typename ParseVisitor, typename NoCaseParseVisitor,typename Skipper> parseboost::spirit::repository::qi::detail::empty_keywords_list520 bool parse( 521 Iterator &/*first*/, 522 const Iterator &/*last*/, 523 const ParseVisitor &/*parse_visitor*/, 524 const NoCaseParseVisitor &/*no_case_parse_visitor*/, 525 const Skipper &/*skipper*/) const 526 { 527 return false; 528 } 529 530 template <typename Iterator,typename ParseVisitor, typename Skipper> parseboost::spirit::repository::qi::detail::empty_keywords_list531 bool parse( 532 Iterator &/*first*/, 533 const Iterator &/*last*/, 534 const ParseVisitor &/*parse_visitor*/, 535 const Skipper &/*skipper*/) const 536 { 537 return false; 538 } 539 540 template <typename ParseFunction> parseboost::spirit::repository::qi::detail::empty_keywords_list541 bool parse( ParseFunction &/*function*/ ) const 542 { 543 return false; 544 } 545 }; 546 547 template<typename ComplexKeywords> 548 struct complex_keywords 549 { 550 // Functor which performs the flag initialization for the complex keyword parsers 551 template <typename FlagsType, typename Elements> 552 struct flag_init_value_setter 553 { 554 typedef int result_type; 555 flag_init_value_setterboost::spirit::repository::qi::detail::complex_keywords::flag_init_value_setter556 flag_init_value_setter(Elements &elements,FlagsType &flags) 557 :flags(flags) 558 ,elements(elements) 559 {} 560 561 template <typename T> operator ()boost::spirit::repository::qi::detail::complex_keywords::flag_init_value_setter562 int operator()(const T &index) const 563 { 564 return call(fusion::at_c<T::value>(elements),index); 565 } 566 567 template <typename T, typename Position, typename Action> callboost::spirit::repository::qi::detail::complex_keywords::flag_init_value_setter568 int call(const spirit::qi::action<T,Action> &parser, const Position /*position*/ ) const 569 { 570 // Get the initial state of the flags array and store it in the flags initializer 571 flags[Position::value]=parser.subject.iter.flag_init(); 572 return 0; 573 } 574 575 template <typename T, typename Position> callboost::spirit::repository::qi::detail::complex_keywords::flag_init_value_setter576 int call( const T & parser, const Position /*position*/) const 577 { 578 // Get the initial state of the flags array and store it in the flags initializer 579 flags[Position::value]=parser.iter.flag_init(); 580 return 0; 581 } 582 583 template <typename T, typename Position> callboost::spirit::repository::qi::detail::complex_keywords::flag_init_value_setter584 int call( const spirit::qi::hold_directive<T> & parser, const Position /*position*/) const 585 { 586 // Get the initial state of the flags array and store it in the flags initializer 587 flags[Position::value]=parser.subject.iter.flag_init(); 588 return 0; 589 } 590 591 FlagsType & flags; 592 Elements &elements; 593 }; 594 595 template <typename Elements, typename Flags> complex_keywordsboost::spirit::repository::qi::detail::complex_keywords596 complex_keywords(Elements &elements, Flags &flags) 597 { 598 flag_init_value_setter<Flags,Elements> flag_initializer(elements,flags); 599 fusion::for_each(complex_keywords_inst,flag_initializer); 600 } 601 602 template <typename ParseFunction> parseboost::spirit::repository::qi::detail::complex_keywords603 bool parse( ParseFunction &function ) const 604 { 605 return fusion::any(complex_keywords_inst,function); 606 } 607 608 ComplexKeywords complex_keywords_inst; 609 }; 610 // This helper class enables jumping over intermediate directives 611 // down the kwd parser iteration count checking policy 612 struct register_successful_parse 613 { 614 template <typename Subject> callboost::spirit::repository::qi::detail::register_successful_parse615 static bool call(Subject const &subject,bool &flag, int &counter) 616 { 617 return subject.iter.register_successful_parse(flag,counter); 618 } 619 template <typename Subject, typename Action> callboost::spirit::repository::qi::detail::register_successful_parse620 static bool call(spirit::qi::action<Subject, Action> const &subject,bool &flag, int &counter) 621 { 622 return subject.subject.iter.register_successful_parse(flag,counter); 623 } 624 template <typename Subject> callboost::spirit::repository::qi::detail::register_successful_parse625 static bool call(spirit::qi::hold_directive<Subject> const &subject,bool &flag, int &counter) 626 { 627 return subject.subject.iter.register_successful_parse(flag,counter); 628 } 629 }; 630 631 // This helper class enables jumping over intermediate directives 632 // down the kwd parser 633 struct extract_keyword 634 { 635 template <typename Subject> callboost::spirit::repository::qi::detail::extract_keyword636 static Subject const& call(Subject const &subject) 637 { 638 return subject; 639 } 640 template <typename Subject, typename Action> callboost::spirit::repository::qi::detail::extract_keyword641 static Subject const& call(spirit::qi::action<Subject, Action> const &subject) 642 { 643 return subject.subject; 644 } 645 template <typename Subject> callboost::spirit::repository::qi::detail::extract_keyword646 static Subject const& call(spirit::qi::hold_directive<Subject> const &subject) 647 { 648 return subject.subject; 649 } 650 }; 651 652 template <typename ParseDispatcher> 653 struct complex_kwd_function 654 { 655 typedef typename ParseDispatcher::iterator_type Iterator; 656 typedef typename ParseDispatcher::context_type Context; 657 typedef typename ParseDispatcher::skipper_type Skipper; complex_kwd_functionboost::spirit::repository::qi::detail::complex_kwd_function658 complex_kwd_function( 659 Iterator& first, Iterator const& last 660 , Context& context, Skipper const& skipper, ParseDispatcher &dispatcher) 661 : first(first) 662 , last(last) 663 , context(context) 664 , skipper(skipper) 665 , dispatcher(dispatcher) 666 { 667 } 668 669 template <typename Component> operator ()boost::spirit::repository::qi::detail::complex_kwd_function670 bool operator()(Component const& component) 671 { 672 Iterator save = first; 673 if( 674 extract_keyword::call( 675 fusion::at_c< 676 Component::value 677 ,typename ParseDispatcher::elements_type 678 >(dispatcher.elements) 679 ) 680 .keyword.parse( 681 first 682 ,last 683 ,context 684 ,skipper 685 ,unused) 686 ) 687 { 688 if(!dispatcher(component)){ 689 first = save; 690 return false; 691 } 692 return true; 693 } 694 return false; 695 } 696 697 Iterator& first; 698 Iterator const& last; 699 Context& context; 700 Skipper const& skipper; 701 ParseDispatcher const& dispatcher; 702 703 // silence MSVC warning C4512: assignment operator could not be generated 704 BOOST_DELETED_FUNCTION(complex_kwd_function& operator= (complex_kwd_function const&)) 705 }; 706 707 708 }}}}} 709 710 #endif 711