/*============================================================================= 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 #include #include #include #include #include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////// // // 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 struct make_const_pointer { private: // T0 shouldn't be of type 'same' BOOST_STATIC_ASSERT((!boost::is_same::value)); typedef typename boost::mpl::if_c< boost::is_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::value, ::phoenix::nil_t, ptr_type >::type type; }; /////////////////////////////////////////////////////////////////////////// template struct assign_zero_to_tuple_member { template static void do_(TupleT &t) { t[phoenix::tuple_index()] = 0; } }; template struct assign_zero_to_tuple_member { template static void do_(TupleT& /*t*/) {} }; struct phoenix_nil_type { typedef ::phoenix::nil_t type; }; template struct init_tuple_member { template static void do_(TupleT &t) { typedef typename boost::mpl::eval_if_c< (N < TupleT::length), ::phoenix::tuple_element, phoenix_nil_type >::type element_type; assign_zero_to_tuple_member::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 // 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::type, // typename impl::make_const_pointer::type, // ... // > tuple_t; // /////////////////////////////////////////////////////////////////////////// #define BOOST_SPIRIT_GRAMMARDEF_TUPLE_PARAM(z, N, _) \ typename impl::make_const_pointer::type \ /**/ typedef ::phoenix::tuple< typename impl::make_const_pointer::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 // 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 \ 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::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 typename ::phoenix::tuple_element::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()]); return t[phoenix::tuple_index()]; } 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