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