Line data Source code
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 :
60 : 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
66 : 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
167 : 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
198 : 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
275 : 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
305 : 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 :
344 0 : 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
350 0 : parse(ScannerT const &scan) const
351 : {
352 : return do_parse(
353 0 : open >> *(*this | (anychar_p - close)) >> close,
354 0 : scan);
355 : }
356 :
357 : private:
358 : template<typename ParserT, typename ScannerT>
359 : typename parser_result<self_t, ScannerT>::type
360 0 : 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 0 : >(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
389 0 : 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 0 : as_parser<OpenT>::convert(open),
396 0 : as_parser<CloseT>::convert(close)
397 0 : );
398 : }
399 :
400 : ///////////////////////////////////////////////////////////////////////////////
401 : BOOST_SPIRIT_CLASSIC_NAMESPACE_END
402 :
403 : }} // namespace BOOST_SPIRIT_CLASSIC_NS
404 :
405 : #endif
|