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