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

Revision 857, 13.8 KB checked in by igarcia, 19 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_CONFIX_HPP
10#define BOOST_SPIRIT_CONFIX_HPP
11
12///////////////////////////////////////////////////////////////////////////////
13#include <boost/config.hpp>
14#include <boost/spirit/meta/as_parser.hpp>
15#include <boost/spirit/core/composite/operators.hpp>
16#include <boost/spirit/utility/impl/confix.ipp>
17
18///////////////////////////////////////////////////////////////////////////////
19namespace boost { namespace spirit {
20
21///////////////////////////////////////////////////////////////////////////////
22//
23//  confix_parser class
24//
25//      Parses a sequence of 3 sub-matches. This class may
26//      be used to parse structures, where the opening part is possibly
27//      contained in the expression part and the whole sequence is only
28//      parsed after seeing the closing part matching the first opening
29//      subsequence. Example: C-comments:
30//
31//      /* This is a C-comment */
32//
33///////////////////////////////////////////////////////////////////////////////
34
35template<typename NestedT = non_nested, typename LexemeT = non_lexeme>
36struct confix_parser_gen;
37
38template <
39    typename OpenT, typename ExprT, typename CloseT, typename CategoryT,
40    typename NestedT = non_nested, typename LexemeT = non_lexeme
41>
42struct confix_parser :
43    public parser<
44        confix_parser<OpenT, ExprT, CloseT, CategoryT, NestedT, LexemeT>
45    >
46{
47    typedef
48        confix_parser<OpenT, ExprT, CloseT, CategoryT, NestedT, LexemeT>
49        self_t;
50
51    confix_parser(OpenT const &open_, ExprT const &expr_, CloseT const &close_)
52    : open(open_), expr(expr_), close(close_)
53    {}
54
55    template <typename ScannerT>
56    typename parser_result<self_t, ScannerT>::type
57    parse(ScannerT const& scan) const
58    {
59        return impl::confix_parser_type<CategoryT>::
60            parse(NestedT(), LexemeT(), *this, scan, open, expr, close);
61    }
62
63private:
64
65    typename as_parser<OpenT>::type::embed_t open;
66    typename as_parser<ExprT>::type::embed_t expr;
67    typename as_parser<CloseT>::type::embed_t close;
68};
69
70///////////////////////////////////////////////////////////////////////////////
71//
72//  Confix parser generator template
73//
74//      This is a helper for generating a correct confix_parser<> from
75//      auxiliary parameters. There are the following types supported as
76//      parameters yet: parsers, single characters and strings (see
77//      as_parser).
78//
79//      If the body parser is an action_parser_category type parser (a parser
80//      with an attached semantic action) we have to do something special. This
81//      happens, if the user wrote something like:
82//
83//          confix_p(open, body[f], close)
84//
85//      where 'body' is the parser matching the body of the confix sequence
86//      and 'f' is a functor to be called after matching the body. If we would
87//      do nothing, the resulting code would parse the sequence as follows:
88//
89//          start >> (body[f] - close) >> close
90//
91//      what in most cases is not what the user expects.
92//      (If this _is_ what you've expected, then please use the confix_p
93//      generator function 'direct()', which will inhibit
94//      re-attaching the actor to the body parser).
95//
96//      To make the confix parser behave as expected:
97//
98//          start >> (body - close)[f] >> close
99//
100//      the actor attached to the 'body' parser has to be re-attached to the
101//      (body - close) parser construct, which will make the resulting confix
102//      parser 'do the right thing'. This refactoring is done by the help of
103//      the refactoring parsers (see the files refactoring.[hi]pp).
104//
105//      Additionally special care must be taken, if the body parser is a
106//      unary_parser_category type parser as
107//
108//          confix_p(open, *anychar_p, close)
109//
110//      which without any refactoring would result in
111//
112//          start >> (*anychar_p - close) >> close
113//
114//      and will not give the expected result (*anychar_p will eat up all the
115//      input up to the end of the input stream). So we have to refactor this
116//      into:
117//
118//          start >> *(anychar_p - close) >> close
119//
120//      what will give the correct result.
121//
122//      The case, where the body parser is a combination of the two mentioned
123//      problems (i.e. the body parser is a unary parser  with an attached
124//      action), is handled accordingly too:
125//
126//          confix_p(start, (*anychar_p)[f], end)
127//
128//      will be parsed as expected:
129//
130//          start >> (*(anychar_p - end))[f] >> end.
131//
132///////////////////////////////////////////////////////////////////////////////
133
134template<typename NestedT, typename LexemeT>
135struct confix_parser_gen
136{
137    // Generic generator function for creation of concrete confix parsers
138
139    template<typename StartT, typename ExprT, typename EndT>
140    confix_parser<
141        typename as_parser<StartT>::type,
142        typename as_parser<ExprT>::type,
143        typename as_parser<EndT>::type,
144        typename as_parser<ExprT>::type::parser_category_t,
145        NestedT,
146        LexemeT
147    >
148    operator()(
149        StartT const &start_, ExprT const &expr_, EndT const &end_) const
150    {
151        typedef typename as_parser<StartT>::type start_t;
152        typedef typename as_parser<ExprT>::type expr_t;
153        typedef typename as_parser<EndT>::type end_t;
154        typedef
155            typename as_parser<ExprT>::type::parser_category_t
156            parser_category_t;
157
158        typedef
159            confix_parser<
160                start_t, expr_t, end_t, parser_category_t, NestedT, LexemeT
161            >
162            return_t;
163
164        return return_t(
165            as_parser<StartT>::convert(start_),
166            as_parser<ExprT>::convert(expr_),
167            as_parser<EndT>::convert(end_)
168        );
169    }
170
171    // Generic generator function for creation of concrete confix parsers
172    // which have an action directly attached to the ExprT part of the
173    // parser (see comment above, no automatic refactoring)
174
175    template<typename StartT, typename ExprT, typename EndT>
176    confix_parser<
177        typename as_parser<StartT>::type,
178        typename as_parser<ExprT>::type,
179        typename as_parser<EndT>::type,
180        plain_parser_category,   // do not re-attach action
181        NestedT,
182        LexemeT
183    >
184    direct(StartT const &start_, ExprT const &expr_, EndT const &end_) const
185    {
186        typedef typename as_parser<StartT>::type start_t;
187        typedef typename as_parser<ExprT>::type expr_t;
188        typedef typename as_parser<EndT>::type end_t;
189        typedef plain_parser_category parser_category_t;
190
191        typedef
192            confix_parser<
193                start_t, expr_t, end_t, parser_category_t, NestedT, LexemeT
194            >
195            return_t;
196
197        return return_t(
198            as_parser<StartT>::convert(start_),
199            as_parser<ExprT>::convert(expr_),
200            as_parser<EndT>::convert(end_)
201        );
202    }
203};
204
205///////////////////////////////////////////////////////////////////////////////
206//
207//  Predefined non_nested confix parser generators
208//
209///////////////////////////////////////////////////////////////////////////////
210
211const confix_parser_gen<non_nested, non_lexeme> confix_p =
212    confix_parser_gen<non_nested, non_lexeme>();
213
214///////////////////////////////////////////////////////////////////////////////
215//
216//  Comments are special types of confix parsers
217//
218//      Comment parser generator template. This is a helper for generating a
219//      correct confix_parser<> from auxiliary parameters, which is able to
220//      parse comment constructs: (StartToken >> Comment text >> EndToken).
221//
222//      There are the following types supported as parameters yet: parsers,
223//      single characters and strings (see as_parser).
224//
225//      There are two diffenerent predefined comment parser generators
226//      (comment_p and comment_nest_p, see below), which may be used for
227//      creating special comment parsers in two different ways.
228//
229//      If these are used with one parameter, a comment starting with the given
230//      first parser parameter up to the end of the line is matched. So for
231//      instance the following parser matches C++ style comments:
232//
233//          comment_p("//").
234//
235//      If these are used with two parameters, a comment starting with the
236//      first parser parameter up to the second parser parameter is matched.
237//      For instance a C style comment parser should be constrcuted as:
238//
239//          comment_p("/*", "*/").
240//
241//      Please note, that a comment is parsed implicitly as if the whole
242//      comment_p(...) statement were embedded into a lexeme_d[] directive.
243//
244///////////////////////////////////////////////////////////////////////////////
245
246template<typename NestedT>
247struct comment_parser_gen
248{
249    // Generic generator function for creation of concrete comment parsers
250    // from an open token. The newline parser eol_p is used as the
251    // closing token.
252
253    template<typename StartT>
254    confix_parser<
255        typename as_parser<StartT>::type,
256        kleene_star<anychar_parser>,
257        alternative<eol_parser, end_parser>,
258        unary_parser_category,          // there is no action to re-attach
259        NestedT,
260        is_lexeme                       // insert implicit lexeme_d[]
261    >
262    operator() (StartT const &start_) const
263    {
264        typedef typename as_parser<StartT>::type start_t;
265        typedef kleene_star<anychar_parser> expr_t;
266        typedef alternative<eol_parser, end_parser> end_t;
267        typedef unary_parser_category parser_category_t;
268
269        typedef
270            confix_parser<
271                start_t, expr_t, end_t, parser_category_t, NestedT, is_lexeme
272            >
273            return_t;
274
275        return return_t(
276            as_parser<StartT>::convert(start_),
277            *anychar_p,
278            eol_p | end_p
279        );
280    }
281
282    // Generic generator function for creation of concrete comment parsers
283    // from an open and a close tokens.
284
285    template<typename StartT, typename EndT>
286    confix_parser<
287        typename as_parser<StartT>::type,
288        kleene_star<anychar_parser>,
289        typename as_parser<EndT>::type,
290        unary_parser_category,          // there is no action to re-attach
291        NestedT,
292        is_lexeme                       // insert implicit lexeme_d[]
293    >
294    operator() (StartT const &start_, EndT const &end_) const
295    {
296        typedef typename as_parser<StartT>::type start_t;
297        typedef kleene_star<anychar_parser> expr_t;
298        typedef typename as_parser<EndT>::type end_t;
299        typedef unary_parser_category parser_category_t;
300
301        typedef
302            confix_parser<
303                start_t, expr_t, end_t, parser_category_t, NestedT, is_lexeme
304            >
305            return_t;
306
307        return return_t(
308            as_parser<StartT>::convert(start_),
309            *anychar_p,
310            as_parser<EndT>::convert(end_)
311        );
312    }
313};
314
315///////////////////////////////////////////////////////////////////////////////
316//
317//  Predefined non_nested comment parser generator
318//
319///////////////////////////////////////////////////////////////////////////////
320
321const comment_parser_gen<non_nested> comment_p =
322    comment_parser_gen<non_nested>();
323
324///////////////////////////////////////////////////////////////////////////////
325//
326//  comment_nest_parser class
327//
328//      Parses a nested comments.
329//      Example: nested PASCAL-comments:
330//
331//      { This is a { nested } PASCAL-comment }
332//
333///////////////////////////////////////////////////////////////////////////////
334
335template<typename OpenT, typename CloseT>
336struct comment_nest_parser:
337    public parser<comment_nest_parser<OpenT, CloseT> >
338{
339    typedef comment_nest_parser<OpenT, CloseT> self_t;
340
341    comment_nest_parser(OpenT const &open_, CloseT const &close_):
342        open(open_), close(close_)
343    {}
344
345    template<typename ScannerT>
346    typename parser_result<self_t, ScannerT>::type
347        parse(ScannerT const &scan) const
348    {
349        return do_parse(
350            open >> *(*this | (anychar_p - close)) >> close,
351            scan);
352    }
353
354private:
355    template<typename ParserT, typename ScannerT>
356    typename parser_result<self_t, ScannerT>::type
357        do_parse(ParserT const &p, ScannerT const &scan) const
358    {
359        return
360            impl::contiguous_parser_parse<
361                BOOST_DEDUCED_TYPENAME parser_result<ParserT, ScannerT>::type
362            >(p, scan, scan);
363    }
364
365    typename as_parser<OpenT>::type::embed_t open;
366    typename as_parser<CloseT>::type::embed_t close;
367};
368
369///////////////////////////////////////////////////////////////////////////////
370//
371//  Predefined nested comment parser generator
372//
373///////////////////////////////////////////////////////////////////////////////
374
375template<typename OpenT, typename CloseT>
376inline
377comment_nest_parser<
378    typename as_parser<OpenT>::type,
379    typename as_parser<CloseT>::type
380>
381    comment_nest_p(OpenT const &open, CloseT const &close)
382{
383    return
384        comment_nest_parser<
385            BOOST_DEDUCED_TYPENAME as_parser<OpenT>::type,
386            BOOST_DEDUCED_TYPENAME as_parser<CloseT>::type
387        >(
388            as_parser<OpenT>::convert(open),
389            as_parser<CloseT>::convert(close)
390        );
391}
392
393///////////////////////////////////////////////////////////////////////////////
394}} // namespace boost::spirit
395
396#endif
Note: See TracBrowser for help on using the repository browser.