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