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.
307 lines
11 KiB
307 lines
11 KiB
/*============================================================================= |
|
Copyright (c) 2003 Hartmut Kaiser |
|
Copyright (c) 2003 Joel de Guzman |
|
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) |
|
=============================================================================*/ |
|
#if !defined(BOOST_SPIRIT_GRAMMAR_DEF_HPP) |
|
#define BOOST_SPIRIT_GRAMMAR_DEF_HPP |
|
|
|
#include <boost/mpl/if.hpp> |
|
#include <boost/mpl/eval_if.hpp> |
|
#include <boost/type_traits/is_same.hpp> |
|
#include <boost/preprocessor/arithmetic/inc.hpp> |
|
#include <boost/preprocessor/arithmetic/dec.hpp> |
|
#include <boost/preprocessor/enum.hpp> |
|
#include <boost/preprocessor/enum_params.hpp> |
|
#include <boost/preprocessor/repeat.hpp> |
|
#include <boost/preprocessor/repeat_from_to.hpp> |
|
#include <boost/spirit/home/classic/namespace.hpp> |
|
#include <boost/spirit/home/classic/phoenix/tuples.hpp> |
|
#include <boost/spirit/home/classic/core/assert.hpp> |
|
#include <boost/spirit/home/classic/utility/grammar_def_fwd.hpp> |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Spirit predefined maximum grammar start parser limit. This limit defines |
|
// the maximum number of of possible different parsers exposed from a |
|
// particular grammar. This number defaults to 3. |
|
// The actual maximum is rounded up in multiples of 3. Thus, if this value |
|
// is 4, the actual limit is 6. The ultimate maximum limit in this |
|
// implementation is 15. |
|
// |
|
// It should NOT be greater than PHOENIX_LIMIT! |
|
// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
#if !defined(BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT) |
|
#define BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT PHOENIX_LIMIT |
|
#endif |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// ensure BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT <= PHOENIX_LIMIT and |
|
// BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT <= 15 and |
|
// BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT > 0 |
|
// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
BOOST_STATIC_ASSERT(BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT <= PHOENIX_LIMIT); |
|
BOOST_STATIC_ASSERT(BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT <= 15); |
|
BOOST_STATIC_ASSERT(BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT > 0); |
|
|
|
////////////////////////////////////////////////////////////////////////////// |
|
namespace boost { namespace spirit { |
|
|
|
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN |
|
|
|
struct same {}; |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
namespace impl { |
|
|
|
/////////////////////////////////////////////////////////////////////////// |
|
// |
|
// The make_const_pointer meta function allows to generate a T const* |
|
// needed to store the pointer to a given start parser from a grammar. |
|
// |
|
/////////////////////////////////////////////////////////////////////////// |
|
template <typename T0, typename T = T0> |
|
struct make_const_pointer { |
|
|
|
private: |
|
// T0 shouldn't be of type 'same' |
|
BOOST_STATIC_ASSERT((!boost::is_same<T0, same>::value)); |
|
|
|
typedef typename boost::mpl::if_c< |
|
boost::is_same<T, same>::value, |
|
T0 const *, |
|
T const * |
|
>::type |
|
ptr_type; |
|
|
|
public: |
|
// If the type in question is phoenix::nil_t, then the returned type |
|
// is still phoenix::nil_t, otherwise a constant pointer type to the |
|
// inspected type is returned. |
|
typedef typename boost::mpl::if_c< |
|
boost::is_same<T, ::phoenix::nil_t>::value, |
|
::phoenix::nil_t, |
|
ptr_type |
|
>::type |
|
type; |
|
}; |
|
|
|
/////////////////////////////////////////////////////////////////////////// |
|
template <int N, typename ElementT> |
|
struct assign_zero_to_tuple_member { |
|
|
|
template <typename TupleT> |
|
static void do_(TupleT &t) { t[::phoenix::tuple_index<N>()] = 0; } |
|
}; |
|
|
|
template <int N> |
|
struct assign_zero_to_tuple_member<N, ::phoenix::nil_t> { |
|
|
|
template <typename TupleT> |
|
static void do_(TupleT& /*t*/) {} |
|
}; |
|
|
|
struct phoenix_nil_type { |
|
|
|
typedef ::phoenix::nil_t type; |
|
}; |
|
|
|
template <int N> |
|
struct init_tuple_member { |
|
|
|
template <typename TupleT> |
|
static void |
|
do_(TupleT &t) |
|
{ |
|
typedef typename boost::mpl::eval_if_c< |
|
(N < TupleT::length), |
|
::phoenix::tuple_element<N, TupleT>, |
|
phoenix_nil_type |
|
>::type |
|
element_type; |
|
|
|
assign_zero_to_tuple_member<N, element_type>::do_(t); |
|
} |
|
}; |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
} // namespace impl |
|
|
|
/////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// grammar_def class |
|
// |
|
// This class may be used as a base class for the embedded definition |
|
// class inside the grammar<> derived user grammar. |
|
// It exposes the two functions needed for start rule access: |
|
// |
|
// rule<> const &start() const; |
|
// |
|
// and |
|
// |
|
// template <int N> |
|
// rule<> const *get_start_parser() const; |
|
// |
|
// Additionally it exposes a set o 'start_parsers' functions, which are to |
|
// be called by the user to define the parsers to use as start parsers |
|
// of the given grammar. |
|
// |
|
/////////////////////////////////////////////////////////////////////////////// |
|
template < |
|
typename T, |
|
BOOST_PP_ENUM_PARAMS( |
|
BOOST_PP_DEC(BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT_A), typename T) |
|
> |
|
class grammar_def { |
|
|
|
private: |
|
/////////////////////////////////////////////////////////////////////////// |
|
// |
|
// This generates the full tuple type from the given template parameters |
|
// T, T0, ... |
|
// |
|
// typedef ::phoenix::tuple< |
|
// typename impl::make_const_pointer<T>::type, |
|
// typename impl::make_const_pointer<T, T0>::type, |
|
// ... |
|
// > tuple_t; |
|
// |
|
/////////////////////////////////////////////////////////////////////////// |
|
#define BOOST_SPIRIT_GRAMMARDEF_TUPLE_PARAM(z, N, _) \ |
|
typename impl::make_const_pointer<T, BOOST_PP_CAT(T, N)>::type \ |
|
/**/ |
|
|
|
typedef ::phoenix::tuple< |
|
typename impl::make_const_pointer<T>::type, |
|
BOOST_PP_ENUM( |
|
BOOST_PP_DEC(BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT_A), |
|
BOOST_SPIRIT_GRAMMARDEF_TUPLE_PARAM, |
|
_ |
|
) |
|
> tuple_t; |
|
|
|
#undef BOOST_SPIRIT_GRAMMARDEF_TUPLE_PARAM |
|
/////////////////////////////////////////////////////////////////////////// |
|
|
|
protected: |
|
/////////////////////////////////////////////////////////////////////////// |
|
// |
|
// This generates a sequence of 'start_parsers' functions with increasing |
|
// number of arguments, which allow to initialize the tuple members with |
|
// the pointers to the start parsers of the grammar: |
|
// |
|
// template <typename TC0, ...> |
|
// void start_parsers (TC0 const &t0, ...) |
|
// { |
|
// using ::phoenix::tuple_index_names::_1; |
|
// t[_1] = &t0; |
|
// ... |
|
// } |
|
// |
|
// where a TC0 const* must be convertible to a T0 const* |
|
// |
|
/////////////////////////////////////////////////////////////////////////// |
|
#define BOOST_SPIRIT_GRAMMARDEF_ENUM_PARAMS(z, N, _) \ |
|
BOOST_PP_CAT(TC, N) const &BOOST_PP_CAT(t, N) \ |
|
/**/ |
|
#define BOOST_SPIRIT_GRAMMARDEF_ENUM_ASSIGN(z, N, _) \ |
|
using ::phoenix::tuple_index_names::BOOST_PP_CAT(_, BOOST_PP_INC(N)); \ |
|
t[BOOST_PP_CAT(_, BOOST_PP_INC(N))] = &BOOST_PP_CAT(t, N); \ |
|
/**/ |
|
#define BOOST_SPIRIT_GRAMMARDEF_ENUM_START(z, N, _) \ |
|
template <BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_INC(N), typename TC)> \ |
|
void \ |
|
start_parsers(BOOST_PP_ENUM_ ## z(BOOST_PP_INC(N), \ |
|
BOOST_SPIRIT_GRAMMARDEF_ENUM_PARAMS, _) ) \ |
|
{ \ |
|
BOOST_PP_REPEAT_ ## z(BOOST_PP_INC(N), \ |
|
BOOST_SPIRIT_GRAMMARDEF_ENUM_ASSIGN, _) \ |
|
} \ |
|
/**/ |
|
|
|
BOOST_PP_REPEAT( |
|
BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT_A, |
|
BOOST_SPIRIT_GRAMMARDEF_ENUM_START, _) |
|
|
|
#undef BOOST_SPIRIT_GRAMMARDEF_ENUM_START |
|
#undef BOOST_SPIRIT_GRAMMARDEF_ENUM_ASSIGN |
|
#undef BOOST_SPIRIT_GRAMMARDEF_ENUM_PARAMS |
|
/////////////////////////////////////////////////////////////////////////// |
|
|
|
/////////////////////////////////////////////////////////////////////////// |
|
// |
|
// This generates some initialization code, which allows to initialize all |
|
// used tuple members to 0 (zero): |
|
// |
|
// t[_1] = 0; |
|
// impl::init_tuple_member<1>::do_(t); |
|
// ... |
|
// |
|
/////////////////////////////////////////////////////////////////////////// |
|
#define BOOST_SPIRIT_GRAMMARDEF_ENUM_INIT(z, N, _) \ |
|
impl::init_tuple_member<N>::do_(t); \ |
|
/**/ |
|
|
|
grammar_def() |
|
{ |
|
using ::phoenix::tuple_index_names::_1; |
|
t[_1] = 0; |
|
BOOST_PP_REPEAT_FROM_TO( |
|
1, BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT_A, |
|
BOOST_SPIRIT_GRAMMARDEF_ENUM_INIT, _) |
|
} |
|
|
|
#undef BOOST_SPIRIT_GRAMMARDEF_ENUM_INIT |
|
/////////////////////////////////////////////////////////////////////////// |
|
|
|
public: |
|
T const & |
|
start() const |
|
{ |
|
// If the following assertion is fired, you have probably forgot to call |
|
// the start_parser() function from inside the constructor of your |
|
// embedded definition class to initialize the start parsers to be exposed |
|
// from your grammar. |
|
using ::phoenix::tuple_index_names::_1; |
|
BOOST_SPIRIT_ASSERT(0 != t[_1]); |
|
return *t[_1]; |
|
} |
|
|
|
template <int N> |
|
typename ::phoenix::tuple_element<N, tuple_t>::crtype |
|
get_start_parser() const |
|
{ |
|
// If the following expression yields a compiler error, you have probably |
|
// tried to access a start rule, which isn't exposed as such from your |
|
// grammar. |
|
BOOST_STATIC_ASSERT(N > 0 && N < tuple_t::length); |
|
|
|
// If the following assertion is fired, you have probably forgot to call |
|
// the start_parser() function from inside the constructor of your |
|
// embedded definition class to initialize the start parsers to be exposed |
|
// from your grammar. |
|
// Another reason may be, that there is a count mismatch between |
|
// the number of template parameters to the grammar_def<> class and the |
|
// number of parameters used while calling start_parsers(). |
|
BOOST_SPIRIT_ASSERT(0 != t[::phoenix::tuple_index<N>()]); |
|
|
|
return t[::phoenix::tuple_index<N>()]; |
|
} |
|
|
|
private: |
|
tuple_t t; |
|
}; |
|
|
|
#undef BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT_A |
|
|
|
BOOST_SPIRIT_CLASSIC_NAMESPACE_END |
|
|
|
}} // namespace BOOST_SPIRIT_CLASSIC_NS |
|
|
|
#endif // BOOST_SPIRIT_GRAMMAR_DEF_HPP
|
|
|