Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/spirit/utility/lists.hpp @ 33

Last change on this file since 33 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

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