Chris@16: /*============================================================================= Chris@16: Copyright (c) 2003 Hartmut Kaiser Chris@16: http://spirit.sourceforge.net/ Chris@16: Chris@16: Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: =============================================================================*/ Chris@16: #ifndef BOOST_SPIRIT_SWITCH_HPP Chris@16: #define BOOST_SPIRIT_SWITCH_HPP Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // The default_p parser generator template uses the following magic number Chris@16: // as the corresponding case label value inside the generated switch() Chris@16: // statements. If this number conflicts with your code, please pick a Chris@16: // different one. Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: #if !defined(BOOST_SPIRIT_DEFAULTCASE_MAGIC) Chris@16: #define BOOST_SPIRIT_DEFAULTCASE_MAGIC 0x15F97A7 Chris@16: #endif Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // Spirit predefined maximum number of possible case_p/default_p case branch Chris@16: // parsers. Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: #if !defined(BOOST_SPIRIT_SWITCH_CASE_LIMIT) Chris@16: #define BOOST_SPIRIT_SWITCH_CASE_LIMIT 3 Chris@16: #endif // !defined(BOOST_SPIRIT_SWITCH_CASE_LIMIT) Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: #include Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // Ensure BOOST_SPIRIT_SELECT_LIMIT > 0 Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: BOOST_STATIC_ASSERT(BOOST_SPIRIT_SWITCH_CASE_LIMIT > 0); Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: namespace boost { namespace spirit { Chris@16: Chris@16: BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // The switch_parser allows to build switch like parsing constructs, which Chris@16: // will have much better perfomance as comparable straight solutions. Chris@16: // Chris@16: // Input stream driven syntax: Chris@16: // Chris@16: // switch_p Chris@16: // [ Chris@16: // case_p<'a'> Chris@16: // (...parser to use, if the next character is 'a'...), Chris@16: // case_p<'b'> Chris@16: // (...parser to use, if the next character is 'b'...), Chris@16: // default_p Chris@16: // (...parser to use, if nothing was matched before...) Chris@16: // ] Chris@16: // Chris@16: // General syntax: Chris@16: // Chris@16: // switch_p(...lazy expression returning the switch condition value...) Chris@16: // [ Chris@16: // case_p<1> Chris@16: // (...parser to use, if the switch condition value is 1...), Chris@16: // case_p<2> Chris@16: // (...parser to use, if the switch condition value is 2...), Chris@16: // default_p Chris@16: // (...parser to use, if nothing was matched before...) Chris@16: // ] Chris@16: // Chris@16: // The maximum number of possible case_p branches is defined by the p constant Chris@16: // BOOST_SPIRIT_SWITCH_CASE_LIMIT (this value defaults to 3 if not otherwise Chris@16: // defined). Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct switch_parser Chris@16: : public unary > > Chris@16: { Chris@16: typedef switch_parser self_t; Chris@16: typedef unary_parser_category parser_category_t; Chris@16: typedef unary > base_t; Chris@16: Chris@16: switch_parser(CaseT const &case_) Chris@16: : base_t(case_), cond(CondT()) Chris@16: {} Chris@16: Chris@16: switch_parser(CaseT const &case_, CondT const &cond_) Chris@16: : base_t(case_), cond(cond_) Chris@16: {} Chris@16: Chris@16: template Chris@16: struct result Chris@16: { Chris@16: typedef typename match_result::type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: typename parser_result::type Chris@16: parse(ScannerT const& scan) const Chris@16: { Chris@16: return this->subject().parse(scan, Chris@16: impl::make_cond_functor::do_(cond)); Chris@16: } Chris@16: Chris@16: CondT cond; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct switch_cond_parser Chris@16: { Chris@16: switch_cond_parser(CondT const &cond_) Chris@16: : cond(cond_) Chris@16: {} Chris@16: Chris@16: template Chris@16: switch_parser Chris@16: operator[](parser const &p) const Chris@16: { Chris@16: return switch_parser(p.derived(), cond); Chris@16: } Chris@16: Chris@16: CondT const &cond; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct case_parser Chris@16: : public unary > > Chris@16: { Chris@16: typedef case_parser self_t; Chris@16: typedef unary_parser_category parser_category_t; Chris@16: typedef unary > base_t; Chris@16: Chris@16: typedef typename base_t::subject_t self_subject_t; Chris@16: Chris@16: BOOST_STATIC_CONSTANT(int, value = N); Chris@16: BOOST_STATIC_CONSTANT(bool, is_default = IsDefault); Chris@16: BOOST_STATIC_CONSTANT(bool, is_simple = true); Chris@16: BOOST_STATIC_CONSTANT(bool, is_epsilon = ( Chris@16: is_default && boost::is_same::value Chris@16: )); Chris@16: Chris@16: case_parser(parser const &p) Chris@16: : base_t(p.derived()) Chris@16: {} Chris@16: Chris@16: template Chris@16: struct result Chris@16: { Chris@16: typedef typename match_result::type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: typename parser_result::type Chris@16: parse(ScannerT const& scan, CondT const &cond) const Chris@16: { Chris@16: typedef impl::default_case default_t; Chris@16: Chris@16: if (!scan.at_end()) { Chris@16: typedef impl::default_delegate_parse< Chris@16: value, is_default, default_t::value> default_parse_t; Chris@16: Chris@16: typename ScannerT::iterator_t const save(scan.first); Chris@16: return default_parse_t::parse(cond(scan), *this, Chris@16: *this, scan, save); Chris@16: } Chris@16: Chris@16: return default_t::is_epsilon ? scan.empty_match() : scan.no_match(); Chris@16: } Chris@16: Chris@16: template Chris@16: impl::compound_case_parser< Chris@16: self_t, case_parser, IsDefault1 Chris@16: > Chris@16: operator, (case_parser const &p) const Chris@16: { Chris@16: // If the following compile time assertion fires, you've probably used Chris@16: // more than one default_p case inside the switch_p parser construct. Chris@16: BOOST_STATIC_ASSERT(!is_default || !IsDefault1); Chris@16: Chris@16: typedef case_parser right_t; Chris@16: return impl::compound_case_parser(*this, p); Chris@16: } Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: struct switch_parser_gen { Chris@16: Chris@16: // This generates a switch parser, which is driven by the condition value Chris@16: // returned by the lazy parameter expression 'cond'. This may be a parser, Chris@16: // which result is used or a phoenix actor, which will be dereferenced to Chris@16: // obtain the switch condition value. Chris@16: template Chris@16: switch_cond_parser Chris@16: operator()(CondT const &cond) const Chris@16: { Chris@16: return switch_cond_parser(cond); Chris@16: } Chris@16: Chris@16: // This generates a switch parser, which is driven by the next character/token Chris@16: // found in the input stream. Chris@16: template Chris@16: switch_parser Chris@16: operator[](parser const &p) const Chris@16: { Chris@16: return switch_parser(p.derived()); Chris@16: } Chris@16: }; Chris@16: Chris@16: switch_parser_gen const switch_p = switch_parser_gen(); Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline case_parser Chris@16: case_p(parser const &p) Chris@16: { Chris@16: return case_parser(p); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: struct default_parser_gen Chris@16: : public case_parser Chris@16: { Chris@16: default_parser_gen() Chris@16: : case_parser Chris@16: (epsilon_p) Chris@16: {} Chris@16: Chris@16: template Chris@16: case_parser Chris@16: operator()(parser const &p) const Chris@16: { Chris@16: return case_parser(p); Chris@16: } Chris@16: }; Chris@16: Chris@16: default_parser_gen const default_p = default_parser_gen(); Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: BOOST_SPIRIT_CLASSIC_NAMESPACE_END Chris@16: Chris@16: }} // namespace BOOST_SPIRIT_CLASSIC_NS Chris@16: Chris@16: #endif // BOOST_SPIRIT_SWITCH_HPP