1 /*=============================================================================
2     Copyright (c) 2003 Hartmut Kaiser
3     http://spirit.sourceforge.net/
4 
5   Distributed under the Boost Software License, Version 1.0. (See accompanying
6   file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 =============================================================================*/
8 #ifndef BOOST_SPIRIT_SELECT_HPP
9 #define BOOST_SPIRIT_SELECT_HPP
10 
11 #include <boost/preprocessor/repeat.hpp>
12 #include <boost/preprocessor/enum.hpp>
13 #include <boost/preprocessor/enum_params.hpp>
14 #include <boost/preprocessor/enum_params_with_defaults.hpp>
15 #include <boost/preprocessor/inc.hpp>
16 #include <boost/preprocessor/cat.hpp>
17 #include <boost/preprocessor/facilities/intercept.hpp>
18 
19 #include <boost/spirit/home/classic/namespace.hpp>
20 #include <boost/spirit/home/classic/core/parser.hpp>
21 
22 #include <boost/spirit/home/classic/phoenix/tuples.hpp>
23 
24 ///////////////////////////////////////////////////////////////////////////////
25 //
26 //  Spirit predefined maximum number of possible embedded select_p parsers.
27 //  It should NOT be greater than PHOENIX_LIMIT!
28 //
29 ///////////////////////////////////////////////////////////////////////////////
30 #if !defined(BOOST_SPIRIT_SELECT_LIMIT)
31 #define BOOST_SPIRIT_SELECT_LIMIT PHOENIX_LIMIT
32 #endif // !defined(BOOST_SPIRIT_SELECT_LIMIT)
33 
34 ///////////////////////////////////////////////////////////////////////////////
35 //
36 // ensure   BOOST_SPIRIT_SELECT_LIMIT <= PHOENIX_LIMIT and
37 //          BOOST_SPIRIT_SELECT_LIMIT > 0
38 //          BOOST_SPIRIT_SELECT_LIMIT <= 15
39 //
40 //  [Pushed this down a little to make CW happy with BOOST_STATIC_ASSERT]
41 //  [Otherwise, it complains: 'boost_static_assert_test_42' redefined]
42 //
43 ///////////////////////////////////////////////////////////////////////////////
44 BOOST_STATIC_ASSERT(BOOST_SPIRIT_SELECT_LIMIT <= PHOENIX_LIMIT);
45 BOOST_STATIC_ASSERT(BOOST_SPIRIT_SELECT_LIMIT > 0);
46 BOOST_STATIC_ASSERT(BOOST_SPIRIT_SELECT_LIMIT <= 15);
47 
48 ///////////////////////////////////////////////////////////////////////////////
49 //
50 //  Calculate the required amount of tuple members rounded up to the nearest
51 //  integer dividable by 3
52 //
53 ///////////////////////////////////////////////////////////////////////////////
54 #if BOOST_SPIRIT_SELECT_LIMIT > 12
55 #define BOOST_SPIRIT_SELECT_LIMIT_A     15
56 #elif BOOST_SPIRIT_SELECT_LIMIT > 9
57 #define BOOST_SPIRIT_SELECT_LIMIT_A     12
58 #elif BOOST_SPIRIT_SELECT_LIMIT > 6
59 #define BOOST_SPIRIT_SELECT_LIMIT_A     9
60 #elif BOOST_SPIRIT_SELECT_LIMIT > 3
61 #define BOOST_SPIRIT_SELECT_LIMIT_A     6
62 #else
63 #define BOOST_SPIRIT_SELECT_LIMIT_A     3
64 #endif
65 
66 ///////////////////////////////////////////////////////////////////////////////
67 namespace boost { namespace spirit {
68 
69 BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
70 
71 ///////////////////////////////////////////////////////////////////////////////
72 //
73 //  The select_default_no_fail and select_default_fail structs are used to
74 //  distinguish two different behaviours for the select_parser in case that not
75 //  any of the given sub-parsers match.
76 //
77 //  If the select_parser is used with the select_default_no_fail behaviour,
78 //  then in case of no matching sub-parser the whole select_parser returns an
79 //  empty match and the value -1.
80 //
81 //  If the select_parser is used with the select_default_fail behaviour, then
82 //  in case of no matching sub-parser the whole select_parser fails to match at
83 //  all.
84 //
85 ///////////////////////////////////////////////////////////////////////////////
86 struct select_default_no_fail {};
87 struct select_default_fail {};
88 
89 BOOST_SPIRIT_CLASSIC_NAMESPACE_END
90 
91 }}  // namespace BOOST_SPIRIT_CLASSIC_NS
92 
93 ///////////////////////////////////////////////////////////////////////////////
94 #include <boost/spirit/home/classic/dynamic/impl/select.ipp>
95 
96 ///////////////////////////////////////////////////////////////////////////////
97 namespace boost { namespace spirit {
98 
99 BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
100 
101 ///////////////////////////////////////////////////////////////////////////////
102 template <typename TupleT, typename BehaviourT, typename T>
103 struct select_parser
104 :   public parser<select_parser<TupleT, BehaviourT, T> >
105 {
106     typedef select_parser<TupleT, BehaviourT, T> self_t;
107 
select_parserboost::spirit::select_parser108     select_parser(TupleT const &t_)
109     :   t(t_)
110     {}
111 
112     template <typename ScannerT>
113     struct result
114     {
115         typedef typename match_result<ScannerT, T>::type type;
116     };
117 
118     template <typename ScannerT>
119     typename parser_result<self_t, ScannerT>::type
parseboost::spirit::select_parser120     parse(ScannerT const& scan) const
121     {
122         typedef typename parser_result<self_t, ScannerT>::type result_t;
123 
124         if (!scan.at_end()) {
125             return impl::parse_tuple_element<
126                 TupleT::length, result_t, TupleT, BehaviourT>::do_(t, scan);
127         }
128         return impl::select_match_gen<result_t, BehaviourT>::do_(scan);
129     }
130 
131     TupleT const t;
132 };
133 
134 ///////////////////////////////////////////////////////////////////////////////
135 template <typename BehaviourT, typename T = int>
136 struct select_parser_gen {
137 
138     ///////////////////////////////////////////////////////////////////////////
139     //
140     //  This generates different select_parser_gen::operator()() functions with
141     //  an increasing number of parser parameters:
142     //
143     //      template <typename ParserT0, ...>
144     //      select_parser<
145     //          ::phoenix::tuple<
146     //              typename impl::as_embedded_parser<ParserT0>::type,
147     //              ...
148     //          >,
149     //          BehaviourT,
150     //          T
151     //      >
152     //      operator()(ParserT0 const &p0, ...) const
153     //      {
154     //          typedef impl::as_embedded_parser<ParserT0> parser_t0;
155     //          ...
156     //
157     //          typedef ::phoenix::tuple<
158     //                  parser_t0::type,
159     //                  ...
160     //              > tuple_t;
161     //          typedef select_parser<tuple_t, BehaviourT, T> result_t;
162     //
163     //          return result_t(tuple_t(
164     //                  parser_t0::convert(p0),
165     //                  ...
166     //              ));
167     //      }
168     //
169     //  The number of generated functions depends on the maximum tuple member
170     //  limit defined by the PHOENIX_LIMIT pp constant.
171     //
172     ///////////////////////////////////////////////////////////////////////////
173     #define BOOST_SPIRIT_SELECT_EMBEDDED(z, N, _)                           \
174         typename impl::as_embedded_parser<BOOST_PP_CAT(ParserT, N)>::type   \
175         /**/
176     #define BOOST_SPIRIT_SELECT_EMBEDDED_TYPEDEF(z, N, _)                   \
177         typedef impl::as_embedded_parser<BOOST_PP_CAT(ParserT, N)>          \
178             BOOST_PP_CAT(parser_t, N);                                      \
179         /**/
180     #define BOOST_SPIRIT_SELECT_CONVERT(z, N, _)                            \
181         BOOST_PP_CAT(parser_t, N)::convert(BOOST_PP_CAT(p, N))              \
182         /**/
183 
184     #define BOOST_SPIRIT_SELECT_PARSER(z, N, _)                             \
185         template <                                                          \
186             BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_INC(N), typename ParserT)    \
187         >                                                                   \
188         select_parser<                                                      \
189             ::phoenix::tuple<                                                 \
190                 BOOST_PP_ENUM_ ## z(BOOST_PP_INC(N),                        \
191                     BOOST_SPIRIT_SELECT_EMBEDDED, _)                        \
192             >,                                                              \
193             BehaviourT,                                                     \
194             T                                                               \
195         >                                                                   \
196         operator()(                                                         \
197             BOOST_PP_ENUM_BINARY_PARAMS_Z(z, BOOST_PP_INC(N),               \
198                 ParserT, const &p)                                          \
199         ) const                                                             \
200         {                                                                   \
201             BOOST_PP_REPEAT_ ## z(BOOST_PP_INC(N),                          \
202                 BOOST_SPIRIT_SELECT_EMBEDDED_TYPEDEF, _)                    \
203                                                                             \
204             typedef ::phoenix::tuple<                                         \
205                     BOOST_PP_ENUM_BINARY_PARAMS_Z(z, BOOST_PP_INC(N),       \
206                         typename parser_t, ::type BOOST_PP_INTERCEPT)       \
207                 > tuple_t;                                                  \
208             typedef select_parser<tuple_t, BehaviourT, T> result_t;         \
209                                                                             \
210             return result_t(tuple_t(                                        \
211                     BOOST_PP_ENUM_ ## z(BOOST_PP_INC(N),                    \
212                         BOOST_SPIRIT_SELECT_CONVERT, _)                     \
213                 ));                                                         \
214         }                                                                   \
215         /**/
216 
217     BOOST_PP_REPEAT(BOOST_SPIRIT_SELECT_LIMIT_A,
218         BOOST_SPIRIT_SELECT_PARSER, _)
219 
220     #undef BOOST_SPIRIT_SELECT_PARSER
221     #undef BOOST_SPIRIT_SELECT_CONVERT
222     #undef BOOST_SPIRIT_SELECT_EMBEDDED_TYPEDEF
223     #undef BOOST_SPIRIT_SELECT_EMBEDDED
224     ///////////////////////////////////////////////////////////////////////////
225 };
226 
227 ///////////////////////////////////////////////////////////////////////////////
228 //
229 //  Predefined parser generator helper objects
230 //
231 ///////////////////////////////////////////////////////////////////////////////
232 select_parser_gen<select_default_no_fail> const select_p =
233     select_parser_gen<select_default_no_fail>();
234 
235 select_parser_gen<select_default_fail> const select_fail_p =
236     select_parser_gen<select_default_fail>();
237 
238 #undef BOOST_SPIRIT_SELECT_LIMIT_A
239 
240 ///////////////////////////////////////////////////////////////////////////////
241 BOOST_SPIRIT_CLASSIC_NAMESPACE_END
242 
243 }}  // namespace BOOST_SPIRIT_CLASSIC_NS
244 
245 #endif // BOOST_SPIRIT_SELECT_HPP
246