source: NonGTP/Boost/boost/spirit/utility/lists.hpp @ 857

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