/*============================================================================= | |
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_SELECT_HPP | |
#define BOOST_SPIRIT_SELECT_HPP | |
#include <boost/preprocessor/repeat.hpp> | |
#include <boost/preprocessor/enum.hpp> | |
#include <boost/preprocessor/enum_params.hpp> | |
#include <boost/preprocessor/enum_params_with_defaults.hpp> | |
#include <boost/preprocessor/inc.hpp> | |
#include <boost/preprocessor/cat.hpp> | |
#include <boost/preprocessor/facilities/intercept.hpp> | |
#include <boost/spirit/home/classic/namespace.hpp> | |
#include <boost/spirit/home/classic/core/parser.hpp> | |
#include <boost/spirit/home/classic/phoenix/tuples.hpp> | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// Spirit predefined maximum number of possible embedded select_p parsers. | |
// It should NOT be greater than PHOENIX_LIMIT! | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
#if !defined(BOOST_SPIRIT_SELECT_LIMIT) | |
#define BOOST_SPIRIT_SELECT_LIMIT PHOENIX_LIMIT | |
#endif // !defined(BOOST_SPIRIT_SELECT_LIMIT) | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// ensure BOOST_SPIRIT_SELECT_LIMIT <= PHOENIX_LIMIT and | |
// BOOST_SPIRIT_SELECT_LIMIT > 0 | |
// BOOST_SPIRIT_SELECT_LIMIT <= 15 | |
// | |
// [Pushed this down a little to make CW happy with BOOST_STATIC_ASSERT] | |
// [Otherwise, it complains: 'boost_static_assert_test_42' redefined] | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
BOOST_STATIC_ASSERT(BOOST_SPIRIT_SELECT_LIMIT <= PHOENIX_LIMIT); | |
BOOST_STATIC_ASSERT(BOOST_SPIRIT_SELECT_LIMIT > 0); | |
BOOST_STATIC_ASSERT(BOOST_SPIRIT_SELECT_LIMIT <= 15); | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// Calculate the required amount of tuple members rounded up to the nearest | |
// integer dividable by 3 | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
#if BOOST_SPIRIT_SELECT_LIMIT > 12 | |
#define BOOST_SPIRIT_SELECT_LIMIT_A 15 | |
#elif BOOST_SPIRIT_SELECT_LIMIT > 9 | |
#define BOOST_SPIRIT_SELECT_LIMIT_A 12 | |
#elif BOOST_SPIRIT_SELECT_LIMIT > 6 | |
#define BOOST_SPIRIT_SELECT_LIMIT_A 9 | |
#elif BOOST_SPIRIT_SELECT_LIMIT > 3 | |
#define BOOST_SPIRIT_SELECT_LIMIT_A 6 | |
#else | |
#define BOOST_SPIRIT_SELECT_LIMIT_A 3 | |
#endif | |
/////////////////////////////////////////////////////////////////////////////// | |
namespace boost { namespace spirit { | |
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// The select_default_no_fail and select_default_fail structs are used to | |
// distinguish two different behaviours for the select_parser in case that not | |
// any of the given sub-parsers match. | |
// | |
// If the select_parser is used with the select_default_no_fail behaviour, | |
// then in case of no matching sub-parser the whole select_parser returns an | |
// empty match and the value -1. | |
// | |
// If the select_parser is used with the select_default_fail behaviour, then | |
// in case of no matching sub-parser the whole select_parser fails to match at | |
// all. | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
struct select_default_no_fail {}; | |
struct select_default_fail {}; | |
BOOST_SPIRIT_CLASSIC_NAMESPACE_END | |
}} // namespace BOOST_SPIRIT_CLASSIC_NS | |
/////////////////////////////////////////////////////////////////////////////// | |
#include <boost/spirit/home/classic/dynamic/impl/select.ipp> | |
/////////////////////////////////////////////////////////////////////////////// | |
namespace boost { namespace spirit { | |
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN | |
/////////////////////////////////////////////////////////////////////////////// | |
template <typename TupleT, typename BehaviourT, typename T> | |
struct select_parser | |
: public parser<select_parser<TupleT, BehaviourT, T> > | |
{ | |
typedef select_parser<TupleT, BehaviourT, T> self_t; | |
select_parser(TupleT const &t_) | |
: t(t_) | |
{} | |
template <typename ScannerT> | |
struct result | |
{ | |
typedef typename match_result<ScannerT, T>::type type; | |
}; | |
template <typename ScannerT> | |
typename parser_result<self_t, ScannerT>::type | |
parse(ScannerT const& scan) const | |
{ | |
typedef typename parser_result<self_t, ScannerT>::type result_t; | |
if (!scan.at_end()) { | |
return impl::parse_tuple_element< | |
TupleT::length, result_t, TupleT, BehaviourT>::do_(t, scan); | |
} | |
return impl::select_match_gen<result_t, BehaviourT>::do_(scan); | |
} | |
TupleT const t; | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
template <typename BehaviourT, typename T = int> | |
struct select_parser_gen { | |
/////////////////////////////////////////////////////////////////////////// | |
// | |
// This generates different select_parser_gen::operator()() functions with | |
// an increasing number of parser parameters: | |
// | |
// template <typename ParserT0, ...> | |
// select_parser< | |
// ::phoenix::tuple< | |
// typename impl::as_embedded_parser<ParserT0>::type, | |
// ... | |
// >, | |
// BehaviourT, | |
// T | |
// > | |
// operator()(ParserT0 const &p0, ...) const | |
// { | |
// typedef impl::as_embedded_parser<ParserT0> parser_t0; | |
// ... | |
// | |
// typedef ::phoenix::tuple< | |
// parser_t0::type, | |
// ... | |
// > tuple_t; | |
// typedef select_parser<tuple_t, BehaviourT, T> result_t; | |
// | |
// return result_t(tuple_t( | |
// parser_t0::convert(p0), | |
// ... | |
// )); | |
// } | |
// | |
// The number of generated functions depends on the maximum tuple member | |
// limit defined by the PHOENIX_LIMIT pp constant. | |
// | |
/////////////////////////////////////////////////////////////////////////// | |
#define BOOST_SPIRIT_SELECT_EMBEDDED(z, N, _) \ | |
typename impl::as_embedded_parser<BOOST_PP_CAT(ParserT, N)>::type \ | |
/**/ | |
#define BOOST_SPIRIT_SELECT_EMBEDDED_TYPEDEF(z, N, _) \ | |
typedef impl::as_embedded_parser<BOOST_PP_CAT(ParserT, N)> \ | |
BOOST_PP_CAT(parser_t, N); \ | |
/**/ | |
#define BOOST_SPIRIT_SELECT_CONVERT(z, N, _) \ | |
BOOST_PP_CAT(parser_t, N)::convert(BOOST_PP_CAT(p, N)) \ | |
/**/ | |
#define BOOST_SPIRIT_SELECT_PARSER(z, N, _) \ | |
template < \ | |
BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_INC(N), typename ParserT) \ | |
> \ | |
select_parser< \ | |
::phoenix::tuple< \ | |
BOOST_PP_ENUM_ ## z(BOOST_PP_INC(N), \ | |
BOOST_SPIRIT_SELECT_EMBEDDED, _) \ | |
>, \ | |
BehaviourT, \ | |
T \ | |
> \ | |
operator()( \ | |
BOOST_PP_ENUM_BINARY_PARAMS_Z(z, BOOST_PP_INC(N), \ | |
ParserT, const &p) \ | |
) const \ | |
{ \ | |
BOOST_PP_REPEAT_ ## z(BOOST_PP_INC(N), \ | |
BOOST_SPIRIT_SELECT_EMBEDDED_TYPEDEF, _) \ | |
\ | |
typedef ::phoenix::tuple< \ | |
BOOST_PP_ENUM_BINARY_PARAMS_Z(z, BOOST_PP_INC(N), \ | |
typename parser_t, ::type BOOST_PP_INTERCEPT) \ | |
> tuple_t; \ | |
typedef select_parser<tuple_t, BehaviourT, T> result_t; \ | |
\ | |
return result_t(tuple_t( \ | |
BOOST_PP_ENUM_ ## z(BOOST_PP_INC(N), \ | |
BOOST_SPIRIT_SELECT_CONVERT, _) \ | |
)); \ | |
} \ | |
/**/ | |
BOOST_PP_REPEAT(BOOST_SPIRIT_SELECT_LIMIT_A, | |
BOOST_SPIRIT_SELECT_PARSER, _) | |
#undef BOOST_SPIRIT_SELECT_PARSER | |
#undef BOOST_SPIRIT_SELECT_CONVERT | |
#undef BOOST_SPIRIT_SELECT_EMBEDDED_TYPEDEF | |
#undef BOOST_SPIRIT_SELECT_EMBEDDED | |
/////////////////////////////////////////////////////////////////////////// | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// Predefined parser generator helper objects | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
select_parser_gen<select_default_no_fail> const select_p = | |
select_parser_gen<select_default_no_fail>(); | |
select_parser_gen<select_default_fail> const select_fail_p = | |
select_parser_gen<select_default_fail>(); | |
#undef BOOST_SPIRIT_SELECT_LIMIT_A | |
/////////////////////////////////////////////////////////////////////////////// | |
BOOST_SPIRIT_CLASSIC_NAMESPACE_END | |
}} // namespace BOOST_SPIRIT_CLASSIC_NS | |
#endif // BOOST_SPIRIT_SELECT_HPP |