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