]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Copyright (c) 2002-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_LISTS_HPP | |
9 | #define BOOST_SPIRIT_LISTS_HPP | |
10 | ||
11 | /////////////////////////////////////////////////////////////////////////////// | |
12 | #include <boost/config.hpp> | |
13 | #include <boost/spirit/home/classic/namespace.hpp> | |
14 | #include <boost/spirit/home/classic/meta/as_parser.hpp> | |
15 | #include <boost/spirit/home/classic/core/parser.hpp> | |
16 | #include <boost/spirit/home/classic/core/composite/composite.hpp> | |
17 | ||
18 | #include <boost/spirit/home/classic/utility/lists_fwd.hpp> | |
19 | #include <boost/spirit/home/classic/utility/impl/lists.ipp> | |
20 | ||
21 | /////////////////////////////////////////////////////////////////////////////// | |
22 | namespace boost { namespace spirit { | |
23 | ||
24 | BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN | |
25 | ||
26 | /////////////////////////////////////////////////////////////////////////////// | |
27 | // | |
28 | // list_parser class | |
29 | // | |
30 | // List parsers allow to parse constructs like | |
31 | // | |
32 | // item >> *(delim >> item) | |
33 | // | |
34 | // where 'item' is an auxiliary expression to parse and 'delim' is an | |
35 | // auxiliary delimiter to parse. | |
36 | // | |
37 | // The list_parser class also can match an optional closing delimiter | |
38 | // represented by the 'end' parser at the end of the list: | |
39 | // | |
40 | // item >> *(delim >> item) >> !end. | |
41 | // | |
42 | // If ItemT is an action_parser_category type (parser with an attached | |
43 | // semantic action) we have to do something special. This happens, if the | |
44 | // user wrote something like: | |
45 | // | |
46 | // list_p(item[f], delim) | |
47 | // | |
48 | // where 'item' is the parser matching one item of the list sequence and | |
49 | // 'f' is a functor to be called after matching one item. If we would do | |
50 | // nothing, the resulting code would parse the sequence as follows: | |
51 | // | |
52 | // (item[f] - delim) >> *(delim >> (item[f] - delim)) | |
53 | // | |
54 | // what in most cases is not what the user expects. | |
55 | // (If this _is_ what you've expected, then please use one of the list_p | |
56 | // generator functions 'direct()', which will inhibit re-attaching | |
57 | // the actor to the item parser). | |
58 | // | |
59 | // To make the list parser behave as expected: | |
60 | // | |
61 | // (item - delim)[f] >> *(delim >> (item - delim)[f]) | |
62 | // | |
63 | // the actor attached to the 'item' parser has to be re-attached to the | |
64 | // *(item - delim) parser construct, which will make the resulting list | |
65 | // parser 'do the right thing'. | |
66 | // | |
67 | // Additionally special care must be taken, if the item parser is a | |
68 | // unary_parser_category type parser as | |
69 | // | |
70 | // list_p(*anychar_p, ',') | |
71 | // | |
72 | // which without any refactoring would result in | |
73 | // | |
74 | // (*anychar_p - ch_p(',')) | |
75 | // >> *( ch_p(',') >> (*anychar_p - ch_p(',')) ) | |
76 | // | |
77 | // and will not give the expected result (the first *anychar_p will eat up | |
78 | // all the input up to the end of the input stream). So we have to | |
79 | // refactor this into: | |
80 | // | |
81 | // *(anychar_p - ch_p(',')) | |
82 | // >> *( ch_p(',') >> *(anychar_p - ch_p(',')) ) | |
83 | // | |
84 | // what will give the correct result. | |
85 | // | |
86 | // The case, where the item parser is a combination of the two mentioned | |
87 | // problems (i.e. the item parser is a unary parser with an attached | |
88 | // action), is handled accordingly too: | |
89 | // | |
90 | // list_p((*anychar_p)[f], ',') | |
91 | // | |
92 | // will be parsed as expected: | |
93 | // | |
94 | // (*(anychar_p - ch_p(',')))[f] | |
95 | // >> *( ch_p(',') >> (*(anychar_p - ch_p(',')))[f] ). | |
96 | // | |
97 | /////////////////////////////////////////////////////////////////////////////// | |
98 | template < | |
99 | typename ItemT, typename DelimT, typename EndT, typename CategoryT | |
100 | > | |
101 | struct list_parser : | |
102 | public parser<list_parser<ItemT, DelimT, EndT, CategoryT> > { | |
103 | ||
104 | typedef list_parser<ItemT, DelimT, EndT, CategoryT> self_t; | |
105 | typedef CategoryT parser_category_t; | |
106 | ||
107 | list_parser(ItemT const &item_, DelimT const &delim_, | |
108 | EndT const& end_ = no_list_endtoken()) | |
109 | : item(item_), delim(delim_), end(end_) | |
110 | {} | |
111 | ||
112 | template <typename ScannerT> | |
113 | typename parser_result<self_t, ScannerT>::type | |
114 | parse(ScannerT const& scan) const | |
115 | { | |
116 | return impl::list_parser_type<CategoryT> | |
117 | ::parse(scan, *this, item, delim, end); | |
118 | } | |
119 | ||
120 | private: | |
121 | typename as_parser<ItemT>::type::embed_t item; | |
122 | typename as_parser<DelimT>::type::embed_t delim; | |
123 | typename as_parser<EndT>::type::embed_t end; | |
124 | }; | |
125 | ||
126 | /////////////////////////////////////////////////////////////////////////////// | |
127 | // | |
128 | // List parser generator template | |
129 | // | |
130 | // This is a helper for generating a correct list_parser<> from | |
131 | // auxiliary parameters. There are the following types supported as | |
132 | // parameters yet: parsers, single characters and strings (see | |
133 | // as_parser<> in meta/as_parser.hpp). | |
134 | // | |
135 | // The list_parser_gen by itself can be used for parsing comma separated | |
136 | // lists without item formatting: | |
137 | // | |
138 | // list_p.parse(...) | |
139 | // matches any comma separated list. | |
140 | // | |
141 | // If list_p is used with one parameter, this parameter is used to match | |
142 | // the delimiter: | |
143 | // | |
144 | // list_p(';').parse(...) | |
145 | // matches any semicolon separated list. | |
146 | // | |
147 | // If list_p is used with two parameters, the first parameter is used to | |
148 | // match the items and the second parameter matches the delimiters: | |
149 | // | |
150 | // list_p(uint_p, ',').parse(...) | |
151 | // matches comma separated unsigned integers. | |
152 | // | |
153 | // If list_p is used with three parameters, the first parameter is used | |
154 | // to match the items, the second one is used to match the delimiters and | |
155 | // the third one is used to match an optional ending token sequence: | |
156 | // | |
157 | // list_p(real_p, ';', eol_p).parse(...) | |
158 | // matches a semicolon separated list of real numbers optionally | |
159 | // followed by an end of line. | |
160 | // | |
161 | // The list_p in the previous examples denotes the predefined parser | |
162 | // generator, which should be used to define list parsers (see below). | |
163 | // | |
164 | /////////////////////////////////////////////////////////////////////////////// | |
165 | ||
166 | template <typename CharT = char> | |
167 | struct list_parser_gen : | |
168 | public list_parser<kleene_star<anychar_parser>, chlit<CharT> > | |
169 | { | |
170 | typedef list_parser_gen<CharT> self_t; | |
171 | ||
172 | // construct the list_parser_gen object as an list parser for comma separated | |
173 | // lists without item formatting. | |
174 | list_parser_gen() | |
175 | : list_parser<kleene_star<anychar_parser>, chlit<CharT> > | |
176 | (*anychar_p, chlit<CharT>(',')) | |
177 | {} | |
178 | ||
179 | // The following generator functions should be used under normal circumstances. | |
180 | // (the operator()(...) functions) | |
181 | ||
182 | // Generic generator functions for creation of concrete list parsers, which | |
183 | // support 'normal' syntax: | |
184 | // | |
185 | // item >> *(delim >> item) | |
186 | // | |
187 | // If item isn't given, everything between two delimiters is matched. | |
188 | ||
189 | template<typename DelimT> | |
190 | list_parser< | |
191 | kleene_star<anychar_parser>, | |
192 | typename as_parser<DelimT>::type, | |
193 | no_list_endtoken, | |
194 | unary_parser_category // there is no action to re-attach | |
195 | > | |
196 | operator()(DelimT const &delim_) const | |
197 | { | |
198 | typedef kleene_star<anychar_parser> item_t; | |
199 | typedef typename as_parser<DelimT>::type delim_t; | |
200 | ||
201 | typedef | |
202 | list_parser<item_t, delim_t, no_list_endtoken, unary_parser_category> | |
203 | return_t; | |
204 | ||
205 | return return_t(*anychar_p, as_parser<DelimT>::convert(delim_)); | |
206 | } | |
207 | ||
208 | template<typename ItemT, typename DelimT> | |
209 | list_parser< | |
210 | typename as_parser<ItemT>::type, | |
211 | typename as_parser<DelimT>::type, | |
212 | no_list_endtoken, | |
213 | typename as_parser<ItemT>::type::parser_category_t | |
214 | > | |
215 | operator()(ItemT const &item_, DelimT const &delim_) const | |
216 | { | |
217 | typedef typename as_parser<ItemT>::type item_t; | |
218 | typedef typename as_parser<DelimT>::type delim_t; | |
219 | typedef list_parser<item_t, delim_t, no_list_endtoken, | |
220 | BOOST_DEDUCED_TYPENAME item_t::parser_category_t> | |
221 | return_t; | |
222 | ||
223 | return return_t( | |
224 | as_parser<ItemT>::convert(item_), | |
225 | as_parser<DelimT>::convert(delim_) | |
226 | ); | |
227 | } | |
228 | ||
229 | // Generic generator function for creation of concrete list parsers, which | |
230 | // support 'extended' syntax: | |
231 | // | |
232 | // item >> *(delim >> item) >> !end | |
233 | ||
234 | template<typename ItemT, typename DelimT, typename EndT> | |
235 | list_parser< | |
236 | typename as_parser<ItemT>::type, | |
237 | typename as_parser<DelimT>::type, | |
238 | typename as_parser<EndT>::type, | |
239 | typename as_parser<ItemT>::type::parser_category_t | |
240 | > | |
241 | operator()( | |
242 | ItemT const &item_, DelimT const &delim_, EndT const &end_) const | |
243 | { | |
244 | typedef typename as_parser<ItemT>::type item_t; | |
245 | typedef typename as_parser<DelimT>::type delim_t; | |
246 | typedef typename as_parser<EndT>::type end_t; | |
247 | ||
248 | typedef list_parser<item_t, delim_t, end_t, | |
249 | BOOST_DEDUCED_TYPENAME item_t::parser_category_t> | |
250 | return_t; | |
251 | ||
252 | return return_t( | |
253 | as_parser<ItemT>::convert(item_), | |
254 | as_parser<DelimT>::convert(delim_), | |
255 | as_parser<EndT>::convert(end_) | |
256 | ); | |
257 | } | |
258 | ||
259 | // The following functions should be used, if the 'item' parser has an attached | |
260 | // semantic action or is a unary_parser_category type parser and the structure | |
261 | // of the resulting list parser should _not_ be refactored during parser | |
262 | // construction (see comment above). | |
263 | ||
264 | // Generic generator function for creation of concrete list parsers, which | |
265 | // support 'normal' syntax: | |
266 | // | |
267 | // item >> *(delim >> item) | |
268 | ||
269 | template<typename ItemT, typename DelimT> | |
270 | list_parser< | |
271 | typename as_parser<ItemT>::type, | |
272 | typename as_parser<DelimT>::type, | |
273 | no_list_endtoken, | |
274 | plain_parser_category // inhibit action re-attachment | |
275 | > | |
276 | direct(ItemT const &item_, DelimT const &delim_) const | |
277 | { | |
278 | typedef typename as_parser<ItemT>::type item_t; | |
279 | typedef typename as_parser<DelimT>::type delim_t; | |
280 | typedef list_parser<item_t, delim_t, no_list_endtoken, | |
281 | plain_parser_category> | |
282 | return_t; | |
283 | ||
284 | return return_t( | |
285 | as_parser<ItemT>::convert(item_), | |
286 | as_parser<DelimT>::convert(delim_) | |
287 | ); | |
288 | } | |
289 | ||
290 | // Generic generator function for creation of concrete list parsers, which | |
291 | // support 'extended' syntax: | |
292 | // | |
293 | // item >> *(delim >> item) >> !end | |
294 | ||
295 | template<typename ItemT, typename DelimT, typename EndT> | |
296 | list_parser< | |
297 | typename as_parser<ItemT>::type, | |
298 | typename as_parser<DelimT>::type, | |
299 | typename as_parser<EndT>::type, | |
300 | plain_parser_category // inhibit action re-attachment | |
301 | > | |
302 | direct( | |
303 | ItemT const &item_, DelimT const &delim_, EndT const &end_) const | |
304 | { | |
305 | typedef typename as_parser<ItemT>::type item_t; | |
306 | typedef typename as_parser<DelimT>::type delim_t; | |
307 | typedef typename as_parser<EndT>::type end_t; | |
308 | ||
309 | typedef | |
310 | list_parser<item_t, delim_t, end_t, plain_parser_category> | |
311 | return_t; | |
312 | ||
313 | return return_t( | |
314 | as_parser<ItemT>::convert(item_), | |
315 | as_parser<DelimT>::convert(delim_), | |
316 | as_parser<EndT>::convert(end_) | |
317 | ); | |
318 | } | |
319 | }; | |
320 | ||
321 | /////////////////////////////////////////////////////////////////////////////// | |
322 | // | |
323 | // Predefined list parser generator | |
324 | // | |
325 | // The list_p parser generator can be used | |
326 | // - by itself for parsing comma separated lists without item formatting | |
327 | // or | |
328 | // - for generating list parsers with auxiliary parser parameters | |
329 | // for the 'item', 'delim' and 'end' subsequences. | |
330 | // (see comment above) | |
331 | // | |
332 | /////////////////////////////////////////////////////////////////////////////// | |
333 | const list_parser_gen<> list_p = list_parser_gen<>(); | |
334 | ||
335 | /////////////////////////////////////////////////////////////////////////////// | |
336 | BOOST_SPIRIT_CLASSIC_NAMESPACE_END | |
337 | ||
338 | }} // namespace BOOST_SPIRIT_CLASSIC_NS | |
339 | ||
340 | #endif |