1 | /*============================================================================= |
---|
2 | Copyright (c) 2003 Hartmut Kaiser |
---|
3 | Copyright (c) 2003 Joel de Guzman |
---|
4 | http://spirit.sourceforge.net/ |
---|
5 | |
---|
6 | Use, modification and distribution is subject to the Boost Software |
---|
7 | License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
---|
8 | http://www.boost.org/LICENSE_1_0.txt) |
---|
9 | =============================================================================*/ |
---|
10 | #if !defined(BOOST_SPIRIT_GRAMMAR_DEF_HPP) |
---|
11 | #define BOOST_SPIRIT_GRAMMAR_DEF_HPP |
---|
12 | |
---|
13 | #include <boost/mpl/if.hpp> |
---|
14 | #include <boost/mpl/eval_if.hpp> |
---|
15 | #include <boost/type_traits/is_same.hpp> |
---|
16 | #include <boost/preprocessor/arithmetic/inc.hpp> |
---|
17 | #include <boost/preprocessor/arithmetic/dec.hpp> |
---|
18 | #include <boost/preprocessor/enum.hpp> |
---|
19 | #include <boost/preprocessor/enum_params.hpp> |
---|
20 | #include <boost/preprocessor/repeat.hpp> |
---|
21 | #include <boost/preprocessor/repeat_from_to.hpp> |
---|
22 | #include <boost/spirit/phoenix/tuples.hpp> |
---|
23 | #include <boost/spirit/core/assert.hpp> |
---|
24 | #include <boost/spirit/utility/grammar_def_fwd.hpp> |
---|
25 | |
---|
26 | /////////////////////////////////////////////////////////////////////////////// |
---|
27 | // |
---|
28 | // Spirit predefined maximum grammar start parser limit. This limit defines |
---|
29 | // the maximum number of of possible different parsers exposed from a |
---|
30 | // particular grammar. This number defaults to 3. |
---|
31 | // The actual maximum is rounded up in multiples of 3. Thus, if this value |
---|
32 | // is 4, the actual limit is 6. The ultimate maximum limit in this |
---|
33 | // implementation is 15. |
---|
34 | // |
---|
35 | // It should NOT be greater than PHOENIX_LIMIT! |
---|
36 | // |
---|
37 | /////////////////////////////////////////////////////////////////////////////// |
---|
38 | #if !defined(BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT) |
---|
39 | #define BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT PHOENIX_LIMIT |
---|
40 | #endif |
---|
41 | |
---|
42 | /////////////////////////////////////////////////////////////////////////////// |
---|
43 | // |
---|
44 | // ensure BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT <= PHOENIX_LIMIT and |
---|
45 | // BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT <= 15 and |
---|
46 | // BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT > 0 |
---|
47 | // |
---|
48 | /////////////////////////////////////////////////////////////////////////////// |
---|
49 | BOOST_STATIC_ASSERT(BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT <= PHOENIX_LIMIT); |
---|
50 | BOOST_STATIC_ASSERT(BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT <= 15); |
---|
51 | BOOST_STATIC_ASSERT(BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT > 0); |
---|
52 | |
---|
53 | ////////////////////////////////////////////////////////////////////////////// |
---|
54 | namespace boost { namespace spirit { |
---|
55 | |
---|
56 | struct same {}; |
---|
57 | |
---|
58 | /////////////////////////////////////////////////////////////////////////////// |
---|
59 | namespace impl { |
---|
60 | |
---|
61 | /////////////////////////////////////////////////////////////////////////// |
---|
62 | // |
---|
63 | // The make_const_pointer meta function allows to generate a T const* |
---|
64 | // needed to store the pointer to a given start parser from a grammar. |
---|
65 | // |
---|
66 | /////////////////////////////////////////////////////////////////////////// |
---|
67 | template <typename T0, typename T = T0> |
---|
68 | struct make_const_pointer { |
---|
69 | |
---|
70 | private: |
---|
71 | // T0 shouldn't be of type 'same' |
---|
72 | BOOST_STATIC_ASSERT((!boost::is_same<T0, same>::value)); |
---|
73 | |
---|
74 | typedef typename boost::mpl::if_c< |
---|
75 | boost::is_same<T, same>::value, |
---|
76 | T0 const *, |
---|
77 | T const * |
---|
78 | >::type |
---|
79 | ptr_type; |
---|
80 | |
---|
81 | public: |
---|
82 | // If the type in question is phoenix::nil_t, then the returned type |
---|
83 | // is still phoenix::nil_t, otherwise a constant pointer type to the |
---|
84 | // inspected type is returned. |
---|
85 | typedef typename boost::mpl::if_c< |
---|
86 | boost::is_same<T, phoenix::nil_t>::value, |
---|
87 | phoenix::nil_t, |
---|
88 | ptr_type |
---|
89 | >::type |
---|
90 | type; |
---|
91 | }; |
---|
92 | |
---|
93 | /////////////////////////////////////////////////////////////////////////// |
---|
94 | template <int N, typename ElementT> |
---|
95 | struct assign_zero_to_tuple_member { |
---|
96 | |
---|
97 | template <typename TupleT> |
---|
98 | static void do_(TupleT &t) { t[phoenix::tuple_index<N>()] = 0; } |
---|
99 | }; |
---|
100 | |
---|
101 | template <int N> |
---|
102 | struct assign_zero_to_tuple_member<N, phoenix::nil_t> { |
---|
103 | |
---|
104 | template <typename TupleT> |
---|
105 | static void do_(TupleT& /*t*/) {} |
---|
106 | }; |
---|
107 | |
---|
108 | struct phoenix_nil_type { |
---|
109 | |
---|
110 | typedef phoenix::nil_t type; |
---|
111 | }; |
---|
112 | |
---|
113 | template <int N> |
---|
114 | struct init_tuple_member { |
---|
115 | |
---|
116 | template <typename TupleT> |
---|
117 | static void |
---|
118 | do_(TupleT &t) |
---|
119 | { |
---|
120 | typedef typename boost::mpl::eval_if_c< |
---|
121 | (N < TupleT::length), |
---|
122 | phoenix::tuple_element<N, TupleT>, |
---|
123 | phoenix_nil_type |
---|
124 | >::type |
---|
125 | element_type; |
---|
126 | |
---|
127 | assign_zero_to_tuple_member<N, element_type>::do_(t); |
---|
128 | } |
---|
129 | }; |
---|
130 | |
---|
131 | /////////////////////////////////////////////////////////////////////////////// |
---|
132 | } // namespace impl |
---|
133 | |
---|
134 | /////////////////////////////////////////////////////////////////////////////// |
---|
135 | // |
---|
136 | // grammar_def class |
---|
137 | // |
---|
138 | // This class may be used as a base class for the embedded definition |
---|
139 | // class inside the grammar<> derived user grammar. |
---|
140 | // It exposes the two functions needed for start rule access: |
---|
141 | // |
---|
142 | // rule<> const &start() const; |
---|
143 | // |
---|
144 | // and |
---|
145 | // |
---|
146 | // template <int N> |
---|
147 | // rule<> const *get_start_parser() const; |
---|
148 | // |
---|
149 | // Additionally it exposes a set o 'start_parsers' functions, which are to |
---|
150 | // be called by the user to define the parsers to use as start parsers |
---|
151 | // of the given grammar. |
---|
152 | // |
---|
153 | /////////////////////////////////////////////////////////////////////////////// |
---|
154 | template < |
---|
155 | typename T, |
---|
156 | BOOST_PP_ENUM_PARAMS( |
---|
157 | BOOST_PP_DEC(BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT_A), typename T) |
---|
158 | > |
---|
159 | class grammar_def { |
---|
160 | |
---|
161 | private: |
---|
162 | /////////////////////////////////////////////////////////////////////////// |
---|
163 | // |
---|
164 | // This generates the full tuple type from the given template parameters |
---|
165 | // T, T0, ... |
---|
166 | // |
---|
167 | // typedef phoenix::tuple< |
---|
168 | // typename impl::make_const_pointer<T>::type, |
---|
169 | // typename impl::make_const_pointer<T, T0>::type, |
---|
170 | // ... |
---|
171 | // > tuple_t; |
---|
172 | // |
---|
173 | /////////////////////////////////////////////////////////////////////////// |
---|
174 | #define BOOST_SPIRIT_GRAMMARDEF_TUPLE_PARAM(z, N, _) \ |
---|
175 | typename impl::make_const_pointer<T, BOOST_PP_CAT(T, N)>::type \ |
---|
176 | /**/ |
---|
177 | |
---|
178 | typedef phoenix::tuple< |
---|
179 | typename impl::make_const_pointer<T>::type, |
---|
180 | BOOST_PP_ENUM( |
---|
181 | BOOST_PP_DEC(BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT_A), |
---|
182 | BOOST_SPIRIT_GRAMMARDEF_TUPLE_PARAM, |
---|
183 | _ |
---|
184 | ) |
---|
185 | > tuple_t; |
---|
186 | |
---|
187 | #undef BOOST_SPIRIT_GRAMMARDEF_TUPLE_PARAM |
---|
188 | /////////////////////////////////////////////////////////////////////////// |
---|
189 | |
---|
190 | protected: |
---|
191 | /////////////////////////////////////////////////////////////////////////// |
---|
192 | // |
---|
193 | // This generates a sequence of 'start_parsers' functions with increasing |
---|
194 | // number of arguments, which allow to initialize the tuple members with |
---|
195 | // the pointers to the start parsers of the grammar: |
---|
196 | // |
---|
197 | // template <typename TC0, ...> |
---|
198 | // void start_parsers (TC0 const &t0, ...) |
---|
199 | // { |
---|
200 | // using phoenix::tuple_index_names::_1; |
---|
201 | // t[_1] = &t0; |
---|
202 | // ... |
---|
203 | // } |
---|
204 | // |
---|
205 | // where a TC0 const* must be convertible to a T0 const* |
---|
206 | // |
---|
207 | /////////////////////////////////////////////////////////////////////////// |
---|
208 | #define BOOST_SPIRIT_GRAMMARDEF_ENUM_PARAMS(z, N, _) \ |
---|
209 | BOOST_PP_CAT(TC, N) const &BOOST_PP_CAT(t, N) \ |
---|
210 | /**/ |
---|
211 | #define BOOST_SPIRIT_GRAMMARDEF_ENUM_ASSIGN(z, N, _) \ |
---|
212 | using phoenix::tuple_index_names::BOOST_PP_CAT(_, BOOST_PP_INC(N)); \ |
---|
213 | t[BOOST_PP_CAT(_, BOOST_PP_INC(N))] = &BOOST_PP_CAT(t, N); \ |
---|
214 | /**/ |
---|
215 | #define BOOST_SPIRIT_GRAMMARDEF_ENUM_START(z, N, _) \ |
---|
216 | template <BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_INC(N), typename TC)> \ |
---|
217 | void \ |
---|
218 | start_parsers(BOOST_PP_ENUM_ ## z(BOOST_PP_INC(N), \ |
---|
219 | BOOST_SPIRIT_GRAMMARDEF_ENUM_PARAMS, _) ) \ |
---|
220 | { \ |
---|
221 | BOOST_PP_REPEAT_ ## z(BOOST_PP_INC(N), \ |
---|
222 | BOOST_SPIRIT_GRAMMARDEF_ENUM_ASSIGN, _) \ |
---|
223 | } \ |
---|
224 | /**/ |
---|
225 | |
---|
226 | BOOST_PP_REPEAT( |
---|
227 | BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT_A, |
---|
228 | BOOST_SPIRIT_GRAMMARDEF_ENUM_START, _) |
---|
229 | |
---|
230 | #undef BOOST_SPIRIT_GRAMMARDEF_ENUM_START |
---|
231 | #undef BOOST_SPIRIT_GRAMMARDEF_ENUM_ASSIGN |
---|
232 | #undef BOOST_SPIRIT_GRAMMARDEF_ENUM_PARAMS |
---|
233 | /////////////////////////////////////////////////////////////////////////// |
---|
234 | |
---|
235 | /////////////////////////////////////////////////////////////////////////// |
---|
236 | // |
---|
237 | // This generates some initialization code, which allows to initialize all |
---|
238 | // used tuple members to 0 (zero): |
---|
239 | // |
---|
240 | // t[_1] = 0; |
---|
241 | // impl::init_tuple_member<1>::do_(t); |
---|
242 | // ... |
---|
243 | // |
---|
244 | /////////////////////////////////////////////////////////////////////////// |
---|
245 | #define BOOST_SPIRIT_GRAMMARDEF_ENUM_INIT(z, N, _) \ |
---|
246 | impl::init_tuple_member<N>::do_(t); \ |
---|
247 | /**/ |
---|
248 | |
---|
249 | grammar_def() |
---|
250 | { |
---|
251 | using phoenix::tuple_index_names::_1; |
---|
252 | t[_1] = 0; |
---|
253 | BOOST_PP_REPEAT_FROM_TO( |
---|
254 | 1, BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT_A, |
---|
255 | BOOST_SPIRIT_GRAMMARDEF_ENUM_INIT, _) |
---|
256 | } |
---|
257 | |
---|
258 | #undef BOOST_SPIRIT_GRAMMARDEF_ENUM_INIT |
---|
259 | /////////////////////////////////////////////////////////////////////////// |
---|
260 | |
---|
261 | public: |
---|
262 | T const & |
---|
263 | start() const |
---|
264 | { |
---|
265 | // If the following assertion is fired, you have probably forgot to call |
---|
266 | // the start_parser() function from inside the constructor of your |
---|
267 | // embedded definition class to initialize the start parsers to be exposed |
---|
268 | // from your grammar. |
---|
269 | using phoenix::tuple_index_names::_1; |
---|
270 | BOOST_SPIRIT_ASSERT(0 != t[_1]); |
---|
271 | return *t[_1]; |
---|
272 | } |
---|
273 | |
---|
274 | template <int N> |
---|
275 | typename phoenix::tuple_element<N, tuple_t>::crtype |
---|
276 | get_start_parser() const |
---|
277 | { |
---|
278 | // If the following expression yields a compiler error, you have probably |
---|
279 | // tried to access a start rule, which isn't exposed as such from your |
---|
280 | // grammar. |
---|
281 | BOOST_STATIC_ASSERT(N > 0 && N < tuple_t::length); |
---|
282 | |
---|
283 | // If the following assertion is fired, you have probably forgot to call |
---|
284 | // the start_parser() function from inside the constructor of your |
---|
285 | // embedded definition class to initialize the start parsers to be exposed |
---|
286 | // from your grammar. |
---|
287 | // Another reason may be, that there is a count mismatch between |
---|
288 | // the number of template parameters to the grammar_def<> class and the |
---|
289 | // number of parameters used while calling start_parsers(). |
---|
290 | BOOST_SPIRIT_ASSERT(0 != t[phoenix::tuple_index<N>()]); |
---|
291 | |
---|
292 | return t[phoenix::tuple_index<N>()]; |
---|
293 | } |
---|
294 | |
---|
295 | private: |
---|
296 | tuple_t t; |
---|
297 | }; |
---|
298 | |
---|
299 | #undef BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT_A |
---|
300 | |
---|
301 | }} // namespace boost::spirit |
---|
302 | |
---|
303 | #endif // BOOST_SPIRIT_GRAMMAR_DEF_HPP |
---|