sl@0
|
1 |
/*=============================================================================
|
sl@0
|
2 |
Copyright (c) 2003 Hartmut Kaiser
|
sl@0
|
3 |
http://spirit.sourceforge.net/
|
sl@0
|
4 |
|
sl@0
|
5 |
Use, modification and distribution is subject to the Boost Software
|
sl@0
|
6 |
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
sl@0
|
7 |
http://www.boost.org/LICENSE_1_0.txt)
|
sl@0
|
8 |
=============================================================================*/
|
sl@0
|
9 |
#ifndef BOOST_SPIRIT_SWITCH_HPP
|
sl@0
|
10 |
#define BOOST_SPIRIT_SWITCH_HPP
|
sl@0
|
11 |
|
sl@0
|
12 |
///////////////////////////////////////////////////////////////////////////////
|
sl@0
|
13 |
//
|
sl@0
|
14 |
// The default_p parser generator template uses the following magic number
|
sl@0
|
15 |
// as the corresponding case label value inside the generated switch()
|
sl@0
|
16 |
// statements. If this number conflicts with your code, please pick a
|
sl@0
|
17 |
// different one.
|
sl@0
|
18 |
//
|
sl@0
|
19 |
///////////////////////////////////////////////////////////////////////////////
|
sl@0
|
20 |
#if !defined(BOOST_SPIRIT_DEFAULTCASE_MAGIC)
|
sl@0
|
21 |
#define BOOST_SPIRIT_DEFAULTCASE_MAGIC 0x15F97A7
|
sl@0
|
22 |
#endif
|
sl@0
|
23 |
|
sl@0
|
24 |
///////////////////////////////////////////////////////////////////////////////
|
sl@0
|
25 |
//
|
sl@0
|
26 |
// Spirit predefined maximum number of possible case_p/default_p case branch
|
sl@0
|
27 |
// parsers.
|
sl@0
|
28 |
//
|
sl@0
|
29 |
///////////////////////////////////////////////////////////////////////////////
|
sl@0
|
30 |
#if !defined(BOOST_SPIRIT_SWITCH_CASE_LIMIT)
|
sl@0
|
31 |
#define BOOST_SPIRIT_SWITCH_CASE_LIMIT 3
|
sl@0
|
32 |
#endif // !defined(BOOST_SPIRIT_SWITCH_CASE_LIMIT)
|
sl@0
|
33 |
|
sl@0
|
34 |
///////////////////////////////////////////////////////////////////////////////
|
sl@0
|
35 |
#include <boost/static_assert.hpp>
|
sl@0
|
36 |
|
sl@0
|
37 |
///////////////////////////////////////////////////////////////////////////////
|
sl@0
|
38 |
//
|
sl@0
|
39 |
// Ensure BOOST_SPIRIT_SELECT_LIMIT > 0
|
sl@0
|
40 |
//
|
sl@0
|
41 |
///////////////////////////////////////////////////////////////////////////////
|
sl@0
|
42 |
BOOST_STATIC_ASSERT(BOOST_SPIRIT_SWITCH_CASE_LIMIT > 0);
|
sl@0
|
43 |
|
sl@0
|
44 |
#include <boost/spirit/core/config.hpp>
|
sl@0
|
45 |
#include <boost/type_traits/is_same.hpp>
|
sl@0
|
46 |
#include <boost/spirit/core/parser.hpp>
|
sl@0
|
47 |
#include <boost/spirit/core/composite/epsilon.hpp>
|
sl@0
|
48 |
#include <boost/spirit/dynamic/impl/switch.ipp>
|
sl@0
|
49 |
|
sl@0
|
50 |
///////////////////////////////////////////////////////////////////////////////
|
sl@0
|
51 |
namespace boost { namespace spirit {
|
sl@0
|
52 |
|
sl@0
|
53 |
///////////////////////////////////////////////////////////////////////////////
|
sl@0
|
54 |
//
|
sl@0
|
55 |
// The switch_parser allows to build switch like parsing constructs, which
|
sl@0
|
56 |
// will have much better perfomance as comparable straight solutions.
|
sl@0
|
57 |
//
|
sl@0
|
58 |
// Input stream driven syntax:
|
sl@0
|
59 |
//
|
sl@0
|
60 |
// switch_p
|
sl@0
|
61 |
// [
|
sl@0
|
62 |
// case_p<'a'>
|
sl@0
|
63 |
// (...parser to use, if the next character is 'a'...),
|
sl@0
|
64 |
// case_p<'b'>
|
sl@0
|
65 |
// (...parser to use, if the next character is 'b'...),
|
sl@0
|
66 |
// default_p
|
sl@0
|
67 |
// (...parser to use, if nothing was matched before...)
|
sl@0
|
68 |
// ]
|
sl@0
|
69 |
//
|
sl@0
|
70 |
// General syntax:
|
sl@0
|
71 |
//
|
sl@0
|
72 |
// switch_p(...lazy expression returning the switch condition value...)
|
sl@0
|
73 |
// [
|
sl@0
|
74 |
// case_p<1>
|
sl@0
|
75 |
// (...parser to use, if the switch condition value is 1...),
|
sl@0
|
76 |
// case_p<2>
|
sl@0
|
77 |
// (...parser to use, if the switch condition value is 2...),
|
sl@0
|
78 |
// default_p
|
sl@0
|
79 |
// (...parser to use, if nothing was matched before...)
|
sl@0
|
80 |
// ]
|
sl@0
|
81 |
//
|
sl@0
|
82 |
// The maximum number of possible case_p branches is defined by the p constant
|
sl@0
|
83 |
// BOOST_SPIRIT_SWITCH_CASE_LIMIT (this value defaults to 3 if not otherwise
|
sl@0
|
84 |
// defined).
|
sl@0
|
85 |
//
|
sl@0
|
86 |
///////////////////////////////////////////////////////////////////////////////
|
sl@0
|
87 |
template <typename CaseT, typename CondT = impl::get_next_token_cond>
|
sl@0
|
88 |
struct switch_parser
|
sl@0
|
89 |
: public unary<CaseT, parser<switch_parser<CaseT, CondT> > >
|
sl@0
|
90 |
{
|
sl@0
|
91 |
typedef switch_parser<CaseT, CondT> self_t;
|
sl@0
|
92 |
typedef unary_parser_category parser_category_t;
|
sl@0
|
93 |
typedef unary<CaseT, parser<self_t> > base_t;
|
sl@0
|
94 |
|
sl@0
|
95 |
switch_parser(CaseT const &case_)
|
sl@0
|
96 |
: base_t(case_), cond(CondT())
|
sl@0
|
97 |
{}
|
sl@0
|
98 |
|
sl@0
|
99 |
switch_parser(CaseT const &case_, CondT const &cond_)
|
sl@0
|
100 |
: base_t(case_), cond(cond_)
|
sl@0
|
101 |
{}
|
sl@0
|
102 |
|
sl@0
|
103 |
template <typename ScannerT>
|
sl@0
|
104 |
struct result
|
sl@0
|
105 |
{
|
sl@0
|
106 |
typedef typename match_result<ScannerT, nil_t>::type type;
|
sl@0
|
107 |
};
|
sl@0
|
108 |
|
sl@0
|
109 |
template <typename ScannerT>
|
sl@0
|
110 |
typename parser_result<self_t, ScannerT>::type
|
sl@0
|
111 |
parse(ScannerT const& scan) const
|
sl@0
|
112 |
{
|
sl@0
|
113 |
return this->subject().parse(scan,
|
sl@0
|
114 |
impl::make_cond_functor<CondT>::do_(cond));
|
sl@0
|
115 |
}
|
sl@0
|
116 |
|
sl@0
|
117 |
CondT cond;
|
sl@0
|
118 |
};
|
sl@0
|
119 |
|
sl@0
|
120 |
///////////////////////////////////////////////////////////////////////////////
|
sl@0
|
121 |
template <typename CondT>
|
sl@0
|
122 |
struct switch_cond_parser
|
sl@0
|
123 |
{
|
sl@0
|
124 |
switch_cond_parser(CondT const &cond_)
|
sl@0
|
125 |
: cond(cond_)
|
sl@0
|
126 |
{}
|
sl@0
|
127 |
|
sl@0
|
128 |
template <typename ParserT>
|
sl@0
|
129 |
switch_parser<ParserT, CondT>
|
sl@0
|
130 |
operator[](parser<ParserT> const &p) const
|
sl@0
|
131 |
{
|
sl@0
|
132 |
return switch_parser<ParserT, CondT>(p.derived(), cond);
|
sl@0
|
133 |
}
|
sl@0
|
134 |
|
sl@0
|
135 |
CondT const &cond;
|
sl@0
|
136 |
};
|
sl@0
|
137 |
|
sl@0
|
138 |
///////////////////////////////////////////////////////////////////////////////
|
sl@0
|
139 |
template <int N, typename ParserT, bool IsDefault>
|
sl@0
|
140 |
struct case_parser
|
sl@0
|
141 |
: public unary<ParserT, parser<case_parser<N, ParserT, IsDefault> > >
|
sl@0
|
142 |
{
|
sl@0
|
143 |
typedef case_parser<N, ParserT, IsDefault> self_t;
|
sl@0
|
144 |
typedef unary_parser_category parser_category_t;
|
sl@0
|
145 |
typedef unary<ParserT, parser<self_t> > base_t;
|
sl@0
|
146 |
|
sl@0
|
147 |
typedef typename base_t::subject_t self_subject_t;
|
sl@0
|
148 |
|
sl@0
|
149 |
BOOST_STATIC_CONSTANT(int, value = N);
|
sl@0
|
150 |
BOOST_STATIC_CONSTANT(bool, is_default = IsDefault);
|
sl@0
|
151 |
BOOST_STATIC_CONSTANT(bool, is_simple = true);
|
sl@0
|
152 |
BOOST_STATIC_CONSTANT(bool, is_epsilon = (
|
sl@0
|
153 |
is_default && boost::is_same<self_subject_t, epsilon_parser>::value
|
sl@0
|
154 |
));
|
sl@0
|
155 |
|
sl@0
|
156 |
case_parser(parser<ParserT> const &p)
|
sl@0
|
157 |
: base_t(p.derived())
|
sl@0
|
158 |
{}
|
sl@0
|
159 |
|
sl@0
|
160 |
template <typename ScannerT>
|
sl@0
|
161 |
struct result
|
sl@0
|
162 |
{
|
sl@0
|
163 |
typedef typename match_result<ScannerT, nil_t>::type type;
|
sl@0
|
164 |
};
|
sl@0
|
165 |
|
sl@0
|
166 |
template <typename ScannerT, typename CondT>
|
sl@0
|
167 |
typename parser_result<self_t, ScannerT>::type
|
sl@0
|
168 |
parse(ScannerT const& scan, CondT const &cond) const
|
sl@0
|
169 |
{
|
sl@0
|
170 |
typedef impl::default_case<self_t> default_t;
|
sl@0
|
171 |
|
sl@0
|
172 |
if (!scan.at_end()) {
|
sl@0
|
173 |
typedef impl::default_delegate_parse<
|
sl@0
|
174 |
value, is_default, default_t::value> default_parse_t;
|
sl@0
|
175 |
|
sl@0
|
176 |
typename ScannerT::iterator_t const save(scan.first);
|
sl@0
|
177 |
return default_parse_t::parse(cond(scan), *this,
|
sl@0
|
178 |
*this, scan, save);
|
sl@0
|
179 |
}
|
sl@0
|
180 |
|
sl@0
|
181 |
return default_t::is_epsilon ? scan.empty_match() : scan.no_match();
|
sl@0
|
182 |
}
|
sl@0
|
183 |
|
sl@0
|
184 |
template <int N1, typename ParserT1, bool IsDefault1>
|
sl@0
|
185 |
impl::compound_case_parser<
|
sl@0
|
186 |
self_t, case_parser<N1, ParserT1, IsDefault1>, IsDefault1
|
sl@0
|
187 |
>
|
sl@0
|
188 |
operator, (case_parser<N1, ParserT1, IsDefault1> const &p) const
|
sl@0
|
189 |
{
|
sl@0
|
190 |
// If the following compile time assertion fires, you've probably used
|
sl@0
|
191 |
// more than one default_p case inside the switch_p parser construct.
|
sl@0
|
192 |
BOOST_STATIC_ASSERT(!is_default || !IsDefault1);
|
sl@0
|
193 |
|
sl@0
|
194 |
typedef case_parser<N1, ParserT1, IsDefault1> right_t;
|
sl@0
|
195 |
return impl::compound_case_parser<self_t, right_t, IsDefault1>(*this, p);
|
sl@0
|
196 |
}
|
sl@0
|
197 |
};
|
sl@0
|
198 |
|
sl@0
|
199 |
///////////////////////////////////////////////////////////////////////////////
|
sl@0
|
200 |
struct switch_parser_gen {
|
sl@0
|
201 |
|
sl@0
|
202 |
// This generates a switch parser, which is driven by the condition value
|
sl@0
|
203 |
// returned by the lazy parameter expression 'cond'. This may be a parser,
|
sl@0
|
204 |
// which result is used or a phoenix actor, which will be dereferenced to
|
sl@0
|
205 |
// obtain the switch condition value.
|
sl@0
|
206 |
template <typename CondT>
|
sl@0
|
207 |
switch_cond_parser<CondT>
|
sl@0
|
208 |
operator()(CondT const &cond) const
|
sl@0
|
209 |
{
|
sl@0
|
210 |
return switch_cond_parser<CondT>(cond);
|
sl@0
|
211 |
}
|
sl@0
|
212 |
|
sl@0
|
213 |
// This generates a switch parser, which is driven by the next character/token
|
sl@0
|
214 |
// found in the input stream.
|
sl@0
|
215 |
template <typename CaseT>
|
sl@0
|
216 |
switch_parser<CaseT>
|
sl@0
|
217 |
operator[](parser<CaseT> const &p) const
|
sl@0
|
218 |
{
|
sl@0
|
219 |
return switch_parser<CaseT>(p.derived());
|
sl@0
|
220 |
}
|
sl@0
|
221 |
};
|
sl@0
|
222 |
|
sl@0
|
223 |
switch_parser_gen const switch_p = switch_parser_gen();
|
sl@0
|
224 |
|
sl@0
|
225 |
///////////////////////////////////////////////////////////////////////////////
|
sl@0
|
226 |
template <int N, typename ParserT>
|
sl@0
|
227 |
inline case_parser<N, ParserT, false>
|
sl@0
|
228 |
case_p(parser<ParserT> const &p)
|
sl@0
|
229 |
{
|
sl@0
|
230 |
return case_parser<N, ParserT, false>(p);
|
sl@0
|
231 |
}
|
sl@0
|
232 |
|
sl@0
|
233 |
///////////////////////////////////////////////////////////////////////////////
|
sl@0
|
234 |
struct default_parser_gen
|
sl@0
|
235 |
: public case_parser<BOOST_SPIRIT_DEFAULTCASE_MAGIC, epsilon_parser, true>
|
sl@0
|
236 |
{
|
sl@0
|
237 |
default_parser_gen()
|
sl@0
|
238 |
: case_parser<BOOST_SPIRIT_DEFAULTCASE_MAGIC, epsilon_parser, true>
|
sl@0
|
239 |
(epsilon_p)
|
sl@0
|
240 |
{}
|
sl@0
|
241 |
|
sl@0
|
242 |
template <typename ParserT>
|
sl@0
|
243 |
case_parser<BOOST_SPIRIT_DEFAULTCASE_MAGIC, ParserT, true>
|
sl@0
|
244 |
operator()(parser<ParserT> const &p) const
|
sl@0
|
245 |
{
|
sl@0
|
246 |
return case_parser<BOOST_SPIRIT_DEFAULTCASE_MAGIC, ParserT, true>(p);
|
sl@0
|
247 |
}
|
sl@0
|
248 |
};
|
sl@0
|
249 |
|
sl@0
|
250 |
default_parser_gen const default_p = default_parser_gen();
|
sl@0
|
251 |
|
sl@0
|
252 |
///////////////////////////////////////////////////////////////////////////////
|
sl@0
|
253 |
}} // namespace boost::spirit
|
sl@0
|
254 |
|
sl@0
|
255 |
#endif // BOOST_SPIRIT_SWITCH_HPP
|