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