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 
list_parserboost::spirit::list_parser107     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
parseboost::spirit::list_parser114     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.
list_parser_genboost::spirit::list_parser_gen174     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     >
operator ()boost::spirit::list_parser_gen196     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     >
operator ()boost::spirit::list_parser_gen215     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     >
operator ()boost::spirit::list_parser_gen241     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     >
directboost::spirit::list_parser_gen276     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     >
directboost::spirit::list_parser_gen302     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
341