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