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