You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
		
		
		
		
		
			
		
			
				
					
					
						
							405 lines
						
					
					
						
							13 KiB
						
					
					
				
			
		
		
	
	
							405 lines
						
					
					
						
							13 KiB
						
					
					
				| /*============================================================================= | |
|     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_CONFIX_HPP | |
| #define BOOST_SPIRIT_CONFIX_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/composite/operators.hpp> | |
|  | |
| #include <boost/spirit/home/classic/utility/confix_fwd.hpp> | |
| #include <boost/spirit/home/classic/utility/impl/confix.ipp> | |
|  | |
| /////////////////////////////////////////////////////////////////////////////// | |
| namespace boost { namespace spirit { | |
| 
 | |
| BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| // | |
| //  confix_parser class | |
| // | |
| //      Parses a sequence of 3 sub-matches. This class may | |
| //      be used to parse structures, where the opening part is possibly | |
| //      contained in the expression part and the whole sequence is only | |
| //      parsed after seeing the closing part matching the first opening | |
| //      subsequence. Example: C-comments: | |
| // | |
| //      /* This is a C-comment */ | |
| // | |
| /////////////////////////////////////////////////////////////////////////////// | |
|  | |
| #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) | |
| #pragma warning(push) | |
| #pragma warning(disable:4512) //assignment operator could not be generated | |
| #endif | |
|  | |
| template<typename NestedT = non_nested, typename LexemeT = non_lexeme> | |
| struct confix_parser_gen; | |
| 
 | |
| template < | |
|     typename OpenT, typename ExprT, typename CloseT, typename CategoryT, | |
|     typename NestedT, typename LexemeT | |
| > | |
| struct confix_parser : | |
|     public parser< | |
|         confix_parser<OpenT, ExprT, CloseT, CategoryT, NestedT, LexemeT> | |
|     > | |
| { | |
|     typedef | |
|         confix_parser<OpenT, ExprT, CloseT, CategoryT, NestedT, LexemeT> | |
|         self_t; | |
| 
 | |
|     confix_parser(OpenT const &open_, ExprT const &expr_, CloseT const &close_) | |
|     : open(open_), expr(expr_), close(close_) | |
|     {} | |
| 
 | |
|     template <typename ScannerT> | |
|     typename parser_result<self_t, ScannerT>::type | |
|     parse(ScannerT const& scan) const | |
|     { | |
|         return impl::confix_parser_type<CategoryT>:: | |
|             parse(NestedT(), LexemeT(), *this, scan, open, expr, close); | |
|     } | |
| 
 | |
| private: | |
| 
 | |
|     typename as_parser<OpenT>::type::embed_t open; | |
|     typename as_parser<ExprT>::type::embed_t expr; | |
|     typename as_parser<CloseT>::type::embed_t close; | |
| }; | |
| 
 | |
| #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) | |
| #pragma warning(pop) | |
| #endif | |
|  | |
| /////////////////////////////////////////////////////////////////////////////// | |
| // | |
| //  Confix parser generator template | |
| // | |
| //      This is a helper for generating a correct confix_parser<> from | |
| //      auxiliary parameters. There are the following types supported as | |
| //      parameters yet: parsers, single characters and strings (see | |
| //      as_parser). | |
| // | |
| //      If the body parser is an action_parser_category type parser (a parser | |
| //      with an attached semantic action) we have to do something special. This | |
| //      happens, if the user wrote something like: | |
| // | |
| //          confix_p(open, body[f], close) | |
| // | |
| //      where 'body' is the parser matching the body of the confix sequence | |
| //      and 'f' is a functor to be called after matching the body. If we would | |
| //      do nothing, the resulting code would parse the sequence as follows: | |
| // | |
| //          start >> (body[f] - close) >> close | |
| // | |
| //      what in most cases is not what the user expects. | |
| //      (If this _is_ what you've expected, then please use the confix_p | |
| //      generator function 'direct()', which will inhibit | |
| //      re-attaching the actor to the body parser). | |
| // | |
| //      To make the confix parser behave as expected: | |
| // | |
| //          start >> (body - close)[f] >> close | |
| // | |
| //      the actor attached to the 'body' parser has to be re-attached to the | |
| //      (body - close) parser construct, which will make the resulting confix | |
| //      parser 'do the right thing'. This refactoring is done by the help of | |
| //      the refactoring parsers (see the files refactoring.[hi]pp). | |
| // | |
| //      Additionally special care must be taken, if the body parser is a | |
| //      unary_parser_category type parser as | |
| // | |
| //          confix_p(open, *anychar_p, close) | |
| // | |
| //      which without any refactoring would result in | |
| // | |
| //          start >> (*anychar_p - close) >> close | |
| // | |
| //      and will not give the expected result (*anychar_p will eat up all the | |
| //      input up to the end of the input stream). So we have to refactor this | |
| //      into: | |
| // | |
| //          start >> *(anychar_p - close) >> close | |
| // | |
| //      what will give the correct result. | |
| // | |
| //      The case, where the body parser is a combination of the two mentioned | |
| //      problems (i.e. the body parser is a unary parser  with an attached | |
| //      action), is handled accordingly too: | |
| // | |
| //          confix_p(start, (*anychar_p)[f], end) | |
| // | |
| //      will be parsed as expected: | |
| // | |
| //          start >> (*(anychar_p - end))[f] >> end. | |
| // | |
| /////////////////////////////////////////////////////////////////////////////// | |
|  | |
| template<typename NestedT, typename LexemeT> | |
| struct confix_parser_gen | |
| { | |
|     // Generic generator function for creation of concrete confix parsers | |
|  | |
|     template<typename StartT, typename ExprT, typename EndT> | |
|     struct paren_op_result_type | |
|     { | |
|         typedef confix_parser< | |
|             typename as_parser<StartT>::type, | |
|             typename as_parser<ExprT>::type, | |
|             typename as_parser<EndT>::type, | |
|             typename as_parser<ExprT>::type::parser_category_t, | |
|             NestedT, | |
|             LexemeT | |
|         > type; | |
|     }; | |
|    | |
|     template<typename StartT, typename ExprT, typename EndT> | |
|     typename paren_op_result_type<StartT, ExprT, EndT>::type  | |
|     operator()(StartT const &start_, ExprT const &expr_, EndT const &end_) const | |
|     { | |
|         typedef typename paren_op_result_type<StartT,ExprT,EndT>::type  | |
|             return_t; | |
| 
 | |
|         return return_t( | |
|             as_parser<StartT>::convert(start_), | |
|             as_parser<ExprT>::convert(expr_), | |
|             as_parser<EndT>::convert(end_) | |
|         ); | |
|     } | |
| 
 | |
|     // Generic generator function for creation of concrete confix parsers | |
|     // which have an action directly attached to the ExprT part of the | |
|     // parser (see comment above, no automatic refactoring) | |
|  | |
|     template<typename StartT, typename ExprT, typename EndT> | |
|     struct direct_result_type | |
|     { | |
|         typedef confix_parser< | |
|             typename as_parser<StartT>::type, | |
|             typename as_parser<ExprT>::type, | |
|             typename as_parser<EndT>::type, | |
|             plain_parser_category,   // do not re-attach action | |
|             NestedT, | |
|             LexemeT | |
|         > type; | |
|     }; | |
| 
 | |
|     template<typename StartT, typename ExprT, typename EndT> | |
|     typename direct_result_type<StartT,ExprT,EndT>::type | |
|     direct(StartT const &start_, ExprT const &expr_, EndT const &end_) const | |
|     { | |
|         typedef typename direct_result_type<StartT,ExprT,EndT>::type | |
|             return_t; | |
| 
 | |
|         return return_t( | |
|             as_parser<StartT>::convert(start_), | |
|             as_parser<ExprT>::convert(expr_), | |
|             as_parser<EndT>::convert(end_) | |
|         ); | |
|     } | |
| }; | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| // | |
| //  Predefined non_nested confix parser generators | |
| // | |
| /////////////////////////////////////////////////////////////////////////////// | |
|  | |
| const confix_parser_gen<non_nested, non_lexeme> confix_p = | |
|     confix_parser_gen<non_nested, non_lexeme>(); | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| // | |
| //  Comments are special types of confix parsers | |
| // | |
| //      Comment parser generator template. This is a helper for generating a | |
| //      correct confix_parser<> from auxiliary parameters, which is able to | |
| //      parse comment constructs: (StartToken >> Comment text >> EndToken). | |
| // | |
| //      There are the following types supported as parameters yet: parsers, | |
| //      single characters and strings (see as_parser). | |
| // | |
| //      There are two diffenerent predefined comment parser generators | |
| //      (comment_p and comment_nest_p, see below), which may be used for | |
| //      creating special comment parsers in two different ways. | |
| // | |
| //      If these are used with one parameter, a comment starting with the given | |
| //      first parser parameter up to the end of the line is matched. So for | |
| //      instance the following parser matches C++ style comments: | |
| // | |
| //          comment_p("//"). | |
| // | |
| //      If these are used with two parameters, a comment starting with the | |
| //      first parser parameter up to the second parser parameter is matched. | |
| //      For instance a C style comment parser should be constrcuted as: | |
| // | |
| //          comment_p("/*", "*/"). | |
| // | |
| //      Please note, that a comment is parsed implicitly as if the whole | |
| //      comment_p(...) statement were embedded into a lexeme_d[] directive. | |
| // | |
| /////////////////////////////////////////////////////////////////////////////// | |
|  | |
| template<typename NestedT> | |
| struct comment_parser_gen | |
| { | |
|     // Generic generator function for creation of concrete comment parsers | |
|     // from an open token. The newline parser eol_p is used as the | |
|     // closing token. | |
|  | |
|     template<typename StartT> | |
|     struct paren_op1_result_type | |
|     { | |
|         typedef confix_parser< | |
|             typename as_parser<StartT>::type, | |
|             kleene_star<anychar_parser>, | |
|             alternative<eol_parser, end_parser>, | |
|             unary_parser_category,          // there is no action to re-attach | |
|             NestedT, | |
|             is_lexeme                       // insert implicit lexeme_d[] | |
|         > | |
|         type; | |
|     }; | |
| 
 | |
|     template<typename StartT> | |
|     typename paren_op1_result_type<StartT>::type  | |
|     operator() (StartT const &start_) const | |
|     { | |
|         typedef typename paren_op1_result_type<StartT>::type | |
|             return_t; | |
| 
 | |
|         return return_t( | |
|             as_parser<StartT>::convert(start_), | |
|             *anychar_p, | |
|             eol_p | end_p | |
|         ); | |
|     } | |
| 
 | |
|     // Generic generator function for creation of concrete comment parsers | |
|     // from an open and a close tokens. | |
|  | |
|     template<typename StartT, typename EndT> | |
|     struct paren_op2_result_type | |
|     { | |
|         typedef confix_parser< | |
|             typename as_parser<StartT>::type, | |
|             kleene_star<anychar_parser>, | |
|             typename as_parser<EndT>::type, | |
|             unary_parser_category,          // there is no action to re-attach | |
|             NestedT, | |
|             is_lexeme                       // insert implicit lexeme_d[] | |
|         > type; | |
|     }; | |
| 
 | |
|     template<typename StartT, typename EndT> | |
|     typename paren_op2_result_type<StartT,EndT>::type | |
|     operator() (StartT const &start_, EndT const &end_) const | |
|     { | |
|         typedef typename paren_op2_result_type<StartT,EndT>::type | |
|             return_t; | |
| 
 | |
|         return return_t( | |
|             as_parser<StartT>::convert(start_), | |
|             *anychar_p, | |
|             as_parser<EndT>::convert(end_) | |
|         ); | |
|     } | |
| }; | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| // | |
| //  Predefined non_nested comment parser generator | |
| // | |
| /////////////////////////////////////////////////////////////////////////////// | |
|  | |
| const comment_parser_gen<non_nested> comment_p = | |
|     comment_parser_gen<non_nested>(); | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| // | |
| //  comment_nest_parser class | |
| // | |
| //      Parses a nested comments. | |
| //      Example: nested PASCAL-comments: | |
| // | |
| //      { This is a { nested } PASCAL-comment } | |
| // | |
| /////////////////////////////////////////////////////////////////////////////// | |
|  | |
| template<typename OpenT, typename CloseT> | |
| struct comment_nest_parser: | |
|     public parser<comment_nest_parser<OpenT, CloseT> > | |
| { | |
|     typedef comment_nest_parser<OpenT, CloseT> self_t; | |
| 
 | |
|     comment_nest_parser(OpenT const &open_, CloseT const &close_): | |
|         open(open_), close(close_) | |
|     {} | |
| 
 | |
|     template<typename ScannerT> | |
|     typename parser_result<self_t, ScannerT>::type | |
|         parse(ScannerT const &scan) const | |
|     { | |
|         return do_parse( | |
|             open >> *(*this | (anychar_p - close)) >> close, | |
|             scan); | |
|     } | |
| 
 | |
| private: | |
|     template<typename ParserT, typename ScannerT> | |
|     typename parser_result<self_t, ScannerT>::type | |
|         do_parse(ParserT const &p, ScannerT const &scan) const | |
|     { | |
|         return | |
|             impl::contiguous_parser_parse< | |
|                 typename parser_result<ParserT, ScannerT>::type | |
|             >(p, scan, scan); | |
|     } | |
| 
 | |
|     typename as_parser<OpenT>::type::embed_t open; | |
|     typename as_parser<CloseT>::type::embed_t close; | |
| }; | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| // | |
| //  Predefined nested comment parser generator | |
| // | |
| /////////////////////////////////////////////////////////////////////////////// | |
|  | |
| template<typename OpenT, typename CloseT> | |
| struct comment_nest_p_result | |
| { | |
|     typedef comment_nest_parser< | |
|         typename as_parser<OpenT>::type, | |
|         typename as_parser<CloseT>::type | |
|     > type; | |
| }; | |
| 
 | |
| template<typename OpenT, typename CloseT> | |
| inline typename comment_nest_p_result<OpenT,CloseT>::type  | |
| comment_nest_p(OpenT const &open, CloseT const &close) | |
| { | |
|     typedef typename comment_nest_p_result<OpenT,CloseT>::type | |
|         result_t; | |
| 
 | |
|     return result_t( | |
|         as_parser<OpenT>::convert(open), | |
|         as_parser<CloseT>::convert(close) | |
|     ); | |
| } | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////////// | |
| BOOST_SPIRIT_CLASSIC_NAMESPACE_END | |
| 
 | |
| }} // namespace BOOST_SPIRIT_CLASSIC_NS | |
|  | |
| #endif
 | |
| 
 |