You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
		
		
		
		
		
			
		
			
				
					
					
						
							574 lines
						
					
					
						
							21 KiB
						
					
					
				
			
		
		
	
	
							574 lines
						
					
					
						
							21 KiB
						
					
					
				| /*============================================================================= | |
|     Copyright (c) 2003 Hartmut Kaiser | |
|     http://spirit.sourceforge.net/ | |
|  | |
|     Use, modification and distribution is subject to the Boost Software | |
|     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
|     http://www.boost.org/LICENSE_1_0.txt) | |
| =============================================================================*/ | |
| #ifndef BOOST_SPIRIT_SWITCH_IPP | |
| #define BOOST_SPIRIT_SWITCH_IPP | |
|  | |
| #include <boost/mpl/if.hpp> | |
| #include <boost/type_traits/is_same.hpp> | |
| #include <boost/static_assert.hpp> | |
|  | |
| #include <boost/preprocessor/cat.hpp> | |
| #include <boost/preprocessor/inc.hpp> | |
| #include <boost/preprocessor/repeat.hpp> | |
| #include <boost/preprocessor/repeat_from_to.hpp> | |
|  | |
| #include <boost/spirit/home/classic/core/parser.hpp> | |
| #include <boost/spirit/home/classic/core/primitives/primitives.hpp> | |
| #include <boost/spirit/home/classic/core/composite/composite.hpp> | |
| #include <boost/spirit/home/classic/meta/as_parser.hpp> | |
|  | |
| #include <boost/spirit/home/classic/phoenix/actor.hpp> | |
| #include <boost/spirit/home/classic/phoenix/tuples.hpp> | |
|  | |
| /////////////////////////////////////////////////////////////////////////////// | |
| namespace boost { namespace spirit { | |
| 
 | |
| BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN | |
| 
 | |
| // forward declaration | |
| template <int N, typename ParserT, bool IsDefault> struct case_parser; | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| namespace impl { | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| //  parse helper functions | |
| template <typename ParserT, typename ScannerT> | |
| inline typename parser_result<ParserT, ScannerT>::type | |
| delegate_parse(ParserT const &p, ScannerT const &scan, | |
|     typename ScannerT::iterator_t const save) | |
| { | |
|     typedef typename parser_result<ParserT, ScannerT>::type result_t; | |
| 
 | |
|     result_t result (p.subject().parse(scan)); | |
|     if (!result) | |
|         scan.first = save; | |
|     return result; | |
| } | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| //  General default case handling (no default_p case branch given). | |
| //  First try to match the current parser node (if the condition value is | |
| //  matched) and, if that fails, return a no_match | |
| template <int N, bool IsDefault, bool HasDefault> | |
| struct default_delegate_parse { | |
| 
 | |
|     template < | |
|         typename ParserT, typename DefaultT, | |
|         typename ValueT, typename ScannerT | |
|     > | |
|     static typename parser_result<ParserT, ScannerT>::type | |
|     parse (ValueT const &value, ParserT const &p, DefaultT const &, | |
|         ScannerT const &scan, typename ScannerT::iterator_t const save) | |
|     { | |
|         if (value == N) | |
|             return delegate_parse(p, scan, save); | |
|         return scan.no_match(); | |
|     } | |
| }; | |
| 
 | |
| //  The current case parser node is the default parser. | |
| //  Ignore the given case value and try to match the given default parser. | |
| template <int N, bool HasDefault> | |
| struct default_delegate_parse<N, true, HasDefault> { | |
| 
 | |
|     template < | |
|         typename ParserT, typename DefaultT, | |
|         typename ValueT, typename ScannerT | |
|     > | |
|     static typename parser_result<ParserT, ScannerT>::type | |
|     parse (ValueT const& /*value*/, ParserT const &, DefaultT const &d, | |
|         ScannerT const &scan, typename ScannerT::iterator_t const save) | |
|     { | |
|         //  Since there is a default_p case branch defined, the corresponding | |
|         //  parser shouldn't be the nothing_parser | |
|         BOOST_STATIC_ASSERT((!boost::is_same<DefaultT, nothing_parser>::value)); | |
|         return delegate_parse(d, scan, save); | |
|     } | |
| }; | |
| 
 | |
| //  The current case parser node is not the default parser, but there is a | |
| //  default_p branch given inside the switch_p parser. | |
| //  First try to match the current parser node (if the condition value is | |
| //  matched) and, if that fails, match the given default_p parser. | |
| template <int N> | |
| struct default_delegate_parse<N, false, true> { | |
| 
 | |
|     template < | |
|         typename ParserT, typename DefaultT, | |
|         typename ValueT, typename ScannerT | |
|     > | |
|     static typename parser_result<ParserT, ScannerT>::type | |
|     parse (ValueT const &value, ParserT const &p, DefaultT const &d, | |
|         ScannerT const &scan, typename ScannerT::iterator_t const save) | |
|     { | |
|         //  Since there is a default_p case branch defined, the corresponding | |
|         //  parser shouldn't be the nothing_parser | |
|         BOOST_STATIC_ASSERT((!boost::is_same<DefaultT, nothing_parser>::value)); | |
|         if (value == N) | |
|             return delegate_parse(p, scan, save); | |
| 
 | |
|         return delegate_parse(d, scan, save); | |
|     } | |
| }; | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| //  Look through the case parser chain to test, if there is a default case | |
| //  branch defined (returned by 'value'). | |
| template <typename CaseT, bool IsSimple = CaseT::is_simple> | |
| struct default_case; | |
| 
 | |
| //////////////////////////////////////// | |
| template <typename ResultT, bool IsDefault> | |
| struct get_default_parser { | |
| 
 | |
|     template <typename ParserT> | |
|     static ResultT | |
|     get(parser<ParserT> const &p) | |
|     { | |
|         return default_case<typename ParserT::derived_t::left_t>:: | |
|             get(p.derived().left()); | |
|     } | |
| }; | |
| 
 | |
| template <typename ResultT> | |
| struct get_default_parser<ResultT, true> { | |
| 
 | |
|     template <typename ParserT> | |
|     static ResultT | |
|     get(parser<ParserT> const &p) { return p.derived().right(); } | |
| }; | |
| 
 | |
| //////////////////////////////////////// | |
| template <typename CaseT, bool IsSimple> | |
| struct default_case { | |
| 
 | |
|     //  The 'value' constant is true, if the current case_parser or one of its | |
|     //  left siblings is a default_p generated case_parser. | |
|     BOOST_STATIC_CONSTANT(bool, value = | |
|         (CaseT::is_default || default_case<typename CaseT::left_t>::value)); | |
| 
 | |
|     //  The 'is_epsilon' constant is true, if the current case_parser or one of | |
|     //  its left siblings is a default_p generated parser with an attached | |
|     //  epsilon_p (this is generated by the plain default_p). | |
|     BOOST_STATIC_CONSTANT(bool, is_epsilon = ( | |
|         (CaseT::is_default && CaseT::is_epsilon) || | |
|             default_case<typename CaseT::left_t>::is_epsilon | |
|     )); | |
| 
 | |
|     //  The computed 'type' represents the type of the default case branch | |
|     //  parser (if there is one) or nothing_parser (if there isn't any default | |
|     //  case branch). | |
|     typedef typename boost::mpl::if_c< | |
|             CaseT::is_default, typename CaseT::right_embed_t, | |
|             typename default_case<typename CaseT::left_t>::type | |
|         >::type type; | |
| 
 | |
|     //  The get function returns the parser attached to the default case branch | |
|     //  (if there is one) or an instance of a nothing_parser (if there isn't | |
|     //  any default case branch). | |
|     template <typename ParserT> | |
|     static type | |
|     get(parser<ParserT> const &p) | |
|     { return get_default_parser<type, CaseT::is_default>::get(p); } | |
| }; | |
| 
 | |
| //////////////////////////////////////// | |
| template <typename ResultT, bool IsDefault> | |
| struct get_default_parser_simple { | |
| 
 | |
|     template <typename ParserT> | |
|     static ResultT | |
|     get(parser<ParserT> const &p) { return p.derived(); } | |
| }; | |
| 
 | |
| template <typename ResultT> | |
| struct get_default_parser_simple<ResultT, false> { | |
| 
 | |
|     template <typename ParserT> | |
|     static nothing_parser | |
|     get(parser<ParserT> const &) { return nothing_p; } | |
| }; | |
| 
 | |
| //////////////////////////////////////// | |
| //  Specialization of the default_case template for the last (leftmost) element | |
| //  of the case parser chain. | |
| template <typename CaseT> | |
| struct default_case<CaseT, true> { | |
| 
 | |
|     //  The 'value' and 'is_epsilon' constant, the 'type' type and the function | |
|     //  'get' are described above. | |
|  | |
|     BOOST_STATIC_CONSTANT(bool, value = CaseT::is_default); | |
|     BOOST_STATIC_CONSTANT(bool, is_epsilon = ( | |
|         CaseT::is_default && CaseT::is_epsilon | |
|     )); | |
| 
 | |
|     typedef typename boost::mpl::if_c< | |
|             CaseT::is_default, CaseT, nothing_parser | |
|         >::type type; | |
| 
 | |
|     template <typename ParserT> | |
|     static type | |
|     get(parser<ParserT> const &p) | |
|     { return get_default_parser_simple<type, value>::get(p); } | |
| }; | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| //  The case_chain template calculates recursivly the depth of the left | |
| //  subchain of the given case branch node. | |
| template <typename CaseT, bool IsSimple = CaseT::is_simple> | |
| struct case_chain { | |
| 
 | |
|     BOOST_STATIC_CONSTANT(int, depth = ( | |
|         case_chain<typename CaseT::left_t>::depth + 1 | |
|     )); | |
| }; | |
| 
 | |
| template <typename CaseT> | |
| struct case_chain<CaseT, true> { | |
| 
 | |
|     BOOST_STATIC_CONSTANT(int, depth = 0); | |
| }; | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| //  The chain_parser template is used to extract the type and the instance of | |
| //  a left or a right parser, burried arbitrary deep inside the case parser | |
| //  chain. | |
| template <int Depth, typename CaseT> | |
| struct chain_parser { | |
| 
 | |
|     typedef typename CaseT::left_t our_left_t; | |
| 
 | |
|     typedef typename chain_parser<Depth-1, our_left_t>::left_t  left_t; | |
|     typedef typename chain_parser<Depth-1, our_left_t>::right_t right_t; | |
| 
 | |
|     static left_t | |
|     left(CaseT const &p) | |
|     { return chain_parser<Depth-1, our_left_t>::left(p.left()); } | |
| 
 | |
|     static right_t | |
|     right(CaseT const &p) | |
|     { return chain_parser<Depth-1, our_left_t>::right(p.left()); } | |
| }; | |
| 
 | |
| template <typename CaseT> | |
| struct chain_parser<1, CaseT> { | |
| 
 | |
|     typedef typename CaseT::left_t  left_t; | |
|     typedef typename CaseT::right_t right_t; | |
| 
 | |
|     static left_t left(CaseT const &p) { return p.left(); } | |
|     static right_t right(CaseT const &p) { return p.right(); } | |
| }; | |
| 
 | |
| template <typename CaseT> | |
| struct chain_parser<0, CaseT>;      // shouldn't be instantiated | |
|  | |
| /////////////////////////////////////////////////////////////////////////////// | |
| //  Type computing meta function for calculating the type of the return value | |
| //  of the used conditional switch expression | |
| template <typename TargetT, typename ScannerT> | |
| struct condition_result { | |
| 
 | |
|     typedef typename TargetT::template result<ScannerT>::type type; | |
| }; | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| template <typename LeftT, typename RightT, bool IsDefault> | |
| struct compound_case_parser | |
| :   public binary<LeftT, RightT, | |
|         parser<compound_case_parser<LeftT, RightT, IsDefault> > > | |
| { | |
|     typedef compound_case_parser<LeftT, RightT, IsDefault>    self_t; | |
|     typedef binary_parser_category                  parser_category_t; | |
|     typedef binary<LeftT, RightT, parser<self_t> >  base_t; | |
| 
 | |
|     BOOST_STATIC_CONSTANT(int, value = RightT::value); | |
|     BOOST_STATIC_CONSTANT(bool, is_default = IsDefault); | |
|     BOOST_STATIC_CONSTANT(bool, is_simple = false); | |
|     BOOST_STATIC_CONSTANT(bool, is_epsilon = ( | |
|         is_default && | |
|             boost::is_same<typename RightT::subject_t, epsilon_parser>::value | |
|     )); | |
| 
 | |
|     compound_case_parser(parser<LeftT> const &lhs, parser<RightT> const &rhs) | |
|     :   base_t(lhs.derived(), rhs.derived()) | |
|     {} | |
| 
 | |
|     template <typename ScannerT> | |
|     struct result | |
|     { | |
|         typedef typename match_result<ScannerT, nil_t>::type type; | |
|     }; | |
| 
 | |
|     template <typename ScannerT, typename CondT> | |
|     typename parser_result<self_t, ScannerT>::type | |
|     parse(ScannerT const& scan, CondT const &cond) const; | |
| 
 | |
|     template <int N1, typename ParserT1, bool IsDefault1> | |
|     compound_case_parser< | |
|         self_t, case_parser<N1, ParserT1, IsDefault1>, IsDefault1 | |
|     > | |
|     operator, (case_parser<N1, ParserT1, IsDefault1> const &p) const | |
|     { | |
|         //  If the following compile time assertion fires, you've probably used | |
|         //  more than one default_p case inside the switch_p parser construct. | |
|         BOOST_STATIC_ASSERT(!default_case<self_t>::value || !IsDefault1); | |
| 
 | |
|         //  If this compile time assertion fires, you've probably want to use | |
|         //  more case_p/default_p case branches, than possible. | |
|         BOOST_STATIC_ASSERT( | |
|             case_chain<self_t>::depth < BOOST_SPIRIT_SWITCH_CASE_LIMIT | |
|         ); | |
| 
 | |
|         typedef case_parser<N1, ParserT1, IsDefault1> right_t; | |
|         return compound_case_parser<self_t, right_t, IsDefault1>(*this, p); | |
|     } | |
| }; | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| //  The parse_switch::do_ functions dispatch to the correct parser, which is | |
| //  selected through the given conditional switch value. | |
| template <int Value, int Depth, bool IsDefault> | |
| struct parse_switch; | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| // | |
| //  The following generates a couple of parse_switch template specializations | |
| //  with an increasing number of handled case branches (for 1..N). | |
| // | |
| //      template <int Value, bool IsDefault> | |
| //      struct parse_switch<Value, N, IsDefault> { | |
| // | |
| //          template <typename ParserT, typename ScannerT> | |
| //          static typename parser_result<ParserT, ScannerT>::type | |
| //          do_(ParserT const &p, ScannerT const &scan, long cond_value, | |
| //              typename ScannerT::iterator_t const &save) | |
| //          { | |
| //              typedef ParserT left_t0; | |
| //              typedef typename left_t0::left left_t1; | |
| //              ... | |
| // | |
| //              switch (cond_value) { | |
| //              case left_tN::value: | |
| //                  return delegate_parse(chain_parser< | |
| //                          case_chain<ParserT>::depth, ParserT | |
| //                      >::left(p), scan, save); | |
| //              ... | |
| //              case left_t1::value: | |
| //                  return delegate_parse(chain_parser< | |
| //                          1, left_t1 | |
| //                      >::right(p.left()), scan, save); | |
| // | |
| //              case left_t0::value: | |
| //              default: | |
| //                  typedef default_case<ParserT> default_t; | |
| //                  typedef default_delegate_parse< | |
| //                              Value, IsDefault, default_t::value> | |
| //                      default_parse_t; | |
| // | |
| //                  return default_parse_t::parse(cond_value, p.right(), | |
| //                      default_t::get(p), scan, save); | |
| //              } | |
| //          } | |
| //      }; | |
| // | |
| /////////////////////////////////////////////////////////////////////////////// | |
| #define BOOST_SPIRIT_PARSE_SWITCH_TYPEDEFS(z, N, _)                         \ | |
|     typedef typename BOOST_PP_CAT(left_t, N)::left_t                        \ | |
|         BOOST_PP_CAT(left_t, BOOST_PP_INC(N));                              \ | |
|     /**/ | |
|  | |
| #define BOOST_SPIRIT_PARSE_SWITCH_CASES(z, N, _)                            \ | |
|     case (long)(BOOST_PP_CAT(left_t, N)::value):                            \ | |
|         return delegate_parse(chain_parser<N, left_t1>::right(p.left()),    \ | |
|             scan, save);                                                    \ | |
|     /**/ | |
|  | |
| #define BOOST_SPIRIT_PARSE_SWITCHES(z, N, _)                                \ | |
|     template <int Value, bool IsDefault>                                    \ | |
|     struct parse_switch<Value, BOOST_PP_INC(N), IsDefault> {                \ | |
|                                                                             \ | |
|         template <typename ParserT, typename ScannerT>                      \ | |
|         static typename parser_result<ParserT, ScannerT>::type              \ | |
|         do_(ParserT const &p, ScannerT const &scan, long cond_value,        \ | |
|             typename ScannerT::iterator_t const &save)                      \ | |
|         {                                                                   \ | |
|             typedef ParserT left_t0;                                        \ | |
|             BOOST_PP_REPEAT_FROM_TO_ ## z(0, BOOST_PP_INC(N),               \ | |
|                 BOOST_SPIRIT_PARSE_SWITCH_TYPEDEFS, _)                      \ | |
|                                                                             \ | |
|             switch (cond_value) {                                           \ | |
|             case (long)(BOOST_PP_CAT(left_t, BOOST_PP_INC(N))::value):      \ | |
|                 return delegate_parse(                                      \ | |
|                     chain_parser<                                           \ | |
|                         case_chain<ParserT>::depth, ParserT                 \ | |
|                >::left(p), scan, save);                                \ | |
|                                                                             \ | |
|             BOOST_PP_REPEAT_FROM_TO_ ## z(1, BOOST_PP_INC(N),               \ | |
|                 BOOST_SPIRIT_PARSE_SWITCH_CASES, _)                         \ | |
|                                                                             \ | |
|             case (long)(left_t0::value):                                    \ | |
|             default:                                                        \ | |
|                 typedef default_case<ParserT> default_t;                    \ | |
|                 typedef                                                     \ | |
|                     default_delegate_parse<Value, IsDefault, default_t::value> \ | |
|                     default_parse_t;                                        \ | |
|                                                                             \ | |
|                 return default_parse_t::parse(cond_value, p.right(),        \ | |
|                     default_t::get(p), scan, save);                         \ | |
|             }                                                               \ | |
|         }                                                                   \ | |
|     };                                                                      \ | |
|     /**/ | |
|  | |
| BOOST_PP_REPEAT(BOOST_PP_DEC(BOOST_SPIRIT_SWITCH_CASE_LIMIT), | |
|     BOOST_SPIRIT_PARSE_SWITCHES, _) | |
| 
 | |
| #undef BOOST_SPIRIT_PARSE_SWITCH_TYPEDEFS | |
| #undef BOOST_SPIRIT_PARSE_SWITCH_CASES | |
| #undef BOOST_SPIRIT_PARSE_SWITCHES | |
| /////////////////////////////////////////////////////////////////////////////// | |
|  | |
| template <typename LeftT, typename RightT, bool IsDefault> | |
| template <typename ScannerT, typename CondT> | |
| inline typename parser_result< | |
|     compound_case_parser<LeftT, RightT, IsDefault>, ScannerT | |
| >::type | |
| compound_case_parser<LeftT, RightT, IsDefault>:: | |
|     parse(ScannerT const& scan, CondT const &cond) const | |
| { | |
|     scan.at_end();    // allow skipper to take effect | |
|     return parse_switch<value, case_chain<self_t>::depth, is_default>:: | |
|         do_(*this, scan, cond(scan), scan.first); | |
| } | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| //  The switch condition is to be evaluated from a parser result value. | |
| template <typename ParserT> | |
| struct cond_functor { | |
| 
 | |
|     typedef cond_functor<ParserT> self_t; | |
| 
 | |
|     cond_functor(ParserT const &p_) | |
|     :   p(p_) | |
|     {} | |
| 
 | |
|     template <typename ScannerT> | |
|     struct result | |
|     { | |
|         typedef typename parser_result<ParserT, ScannerT>::type::attr_t type; | |
|     }; | |
| 
 | |
|     template <typename ScannerT> | |
|     typename condition_result<self_t, ScannerT>::type | |
|     operator()(ScannerT const &scan) const | |
|     { | |
|         typedef typename parser_result<ParserT, ScannerT>::type result_t; | |
|         typedef typename result_t::attr_t attr_t; | |
| 
 | |
|         result_t result(p.parse(scan)); | |
|         return !result ? attr_t() : result.value(); | |
|     } | |
| 
 | |
|     typename ParserT::embed_t p; | |
| }; | |
| 
 | |
| template <typename ParserT> | |
| struct make_cond_functor { | |
| 
 | |
|     typedef as_parser<ParserT> as_parser_t; | |
| 
 | |
|     static cond_functor<typename as_parser_t::type> | |
|     do_(ParserT const &cond) | |
|     { | |
|         return cond_functor<typename as_parser_t::type>( | |
|             as_parser_t::convert(cond)); | |
|     } | |
| }; | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| //  The switch condition is to be evaluated from a phoenix actor | |
| template <typename ActorT> | |
| struct cond_actor { | |
| 
 | |
|     typedef cond_actor<ActorT> self_t; | |
| 
 | |
|     cond_actor(ActorT const &actor_) | |
|     :   actor(actor_) | |
|     {} | |
| 
 | |
|     template <typename ScannerT> | |
|     struct result | |
|     { | |
|         typedef typename ::phoenix::actor_result<ActorT, ::phoenix::tuple<> >::type | |
|             type; | |
|     }; | |
| 
 | |
|     template <typename ScannerT> | |
|     typename condition_result<self_t, ScannerT>::type | |
|     operator()(ScannerT const& /*scan*/) const | |
|     { | |
|         return actor(); | |
|     } | |
| 
 | |
|     ActorT const &actor; | |
| }; | |
| 
 | |
| template <typename ActorT> | |
| struct make_cond_functor< ::phoenix::actor<ActorT> > { | |
| 
 | |
|     static cond_actor< ::phoenix::actor<ActorT> > | |
|     do_(::phoenix::actor<ActorT> const &actor) | |
|     { | |
|         return cond_actor< ::phoenix::actor<ActorT> >(actor); | |
|     } | |
| }; | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| //  The switch condition is to be taken directly from the input stream | |
| struct get_next_token_cond { | |
| 
 | |
|     typedef get_next_token_cond self_t; | |
| 
 | |
|     template <typename ScannerT> | |
|     struct result | |
|     { | |
|         typedef typename ScannerT::value_t type; | |
|     }; | |
| 
 | |
|     template <typename ScannerT> | |
|     typename condition_result<self_t, ScannerT>::type | |
|     operator()(ScannerT const &scan) const | |
|     { | |
|         typename ScannerT::value_t val(*scan); | |
|         ++scan.first; | |
|         return val; | |
|     } | |
| }; | |
| 
 | |
| template <> | |
| struct make_cond_functor<get_next_token_cond> { | |
| 
 | |
|     static get_next_token_cond | |
|     do_(get_next_token_cond const &cond) | |
|     { | |
|         return cond; | |
|     } | |
| }; | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| }   // namespace impl | |
|  | |
| BOOST_SPIRIT_CLASSIC_NAMESPACE_END | |
| 
 | |
| }}  // namespace boost::spirit | |
|  | |
| #endif  // BOOST_SPIRIT_SWITCH_IPP
 | |
| 
 |