sl@0: /*============================================================================= sl@0: Copyright (c) 2002-2003 Hartmut Kaiser sl@0: http://spirit.sourceforge.net/ sl@0: sl@0: Use, modification and distribution is subject to the Boost Software sl@0: License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at sl@0: http://www.boost.org/LICENSE_1_0.txt) sl@0: =============================================================================*/ sl@0: #ifndef BOOST_SPIRIT_CONFIX_HPP sl@0: #define BOOST_SPIRIT_CONFIX_HPP sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include sl@0: #include sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: namespace boost { namespace spirit { sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: // sl@0: // confix_parser class sl@0: // sl@0: // Parses a sequence of 3 sub-matches. This class may sl@0: // be used to parse structures, where the opening part is possibly sl@0: // contained in the expression part and the whole sequence is only sl@0: // parsed after seeing the closing part matching the first opening sl@0: // subsequence. Example: C-comments: sl@0: // sl@0: // /* This is a C-comment */ sl@0: // sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: template sl@0: struct confix_parser_gen; sl@0: sl@0: template < sl@0: typename OpenT, typename ExprT, typename CloseT, typename CategoryT, sl@0: typename NestedT, typename LexemeT sl@0: > sl@0: struct confix_parser : sl@0: public parser< sl@0: confix_parser sl@0: > sl@0: { sl@0: typedef sl@0: confix_parser sl@0: self_t; sl@0: sl@0: confix_parser(OpenT const &open_, ExprT const &expr_, CloseT const &close_) sl@0: : open(open_), expr(expr_), close(close_) sl@0: {} sl@0: sl@0: template sl@0: typename parser_result::type sl@0: parse(ScannerT const& scan) const sl@0: { sl@0: return impl::confix_parser_type:: sl@0: parse(NestedT(), LexemeT(), *this, scan, open, expr, close); sl@0: } sl@0: sl@0: private: sl@0: sl@0: typename as_parser::type::embed_t open; sl@0: typename as_parser::type::embed_t expr; sl@0: typename as_parser::type::embed_t close; sl@0: }; sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: // sl@0: // Confix parser generator template sl@0: // sl@0: // This is a helper for generating a correct confix_parser<> from sl@0: // auxiliary parameters. There are the following types supported as sl@0: // parameters yet: parsers, single characters and strings (see sl@0: // as_parser). sl@0: // sl@0: // If the body parser is an action_parser_category type parser (a parser sl@0: // with an attached semantic action) we have to do something special. This sl@0: // happens, if the user wrote something like: sl@0: // sl@0: // confix_p(open, body[f], close) sl@0: // sl@0: // where 'body' is the parser matching the body of the confix sequence sl@0: // and 'f' is a functor to be called after matching the body. If we would sl@0: // do nothing, the resulting code would parse the sequence as follows: sl@0: // sl@0: // start >> (body[f] - close) >> close sl@0: // sl@0: // what in most cases is not what the user expects. sl@0: // (If this _is_ what you've expected, then please use the confix_p sl@0: // generator function 'direct()', which will inhibit sl@0: // re-attaching the actor to the body parser). sl@0: // sl@0: // To make the confix parser behave as expected: sl@0: // sl@0: // start >> (body - close)[f] >> close sl@0: // sl@0: // the actor attached to the 'body' parser has to be re-attached to the sl@0: // (body - close) parser construct, which will make the resulting confix sl@0: // parser 'do the right thing'. This refactoring is done by the help of sl@0: // the refactoring parsers (see the files refactoring.[hi]pp). sl@0: // sl@0: // Additionally special care must be taken, if the body parser is a sl@0: // unary_parser_category type parser as sl@0: // sl@0: // confix_p(open, *anychar_p, close) sl@0: // sl@0: // which without any refactoring would result in sl@0: // sl@0: // start >> (*anychar_p - close) >> close sl@0: // sl@0: // and will not give the expected result (*anychar_p will eat up all the sl@0: // input up to the end of the input stream). So we have to refactor this sl@0: // into: sl@0: // sl@0: // start >> *(anychar_p - close) >> close sl@0: // sl@0: // what will give the correct result. sl@0: // sl@0: // The case, where the body parser is a combination of the two mentioned sl@0: // problems (i.e. the body parser is a unary parser with an attached sl@0: // action), is handled accordingly too: sl@0: // sl@0: // confix_p(start, (*anychar_p)[f], end) sl@0: // sl@0: // will be parsed as expected: sl@0: // sl@0: // start >> (*(anychar_p - end))[f] >> end. sl@0: // sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: template sl@0: struct confix_parser_gen sl@0: { sl@0: // Generic generator function for creation of concrete confix parsers sl@0: sl@0: template sl@0: struct paren_op_result_type sl@0: { sl@0: typedef confix_parser< sl@0: typename as_parser::type, sl@0: typename as_parser::type, sl@0: typename as_parser::type, sl@0: typename as_parser::type::parser_category_t, sl@0: NestedT, sl@0: LexemeT sl@0: > type; sl@0: }; sl@0: sl@0: template sl@0: typename paren_op_result_type::type sl@0: operator()(StartT const &start_, ExprT const &expr_, EndT const &end_) const sl@0: { sl@0: typedef typename paren_op_result_type::type sl@0: return_t; sl@0: sl@0: return return_t( sl@0: as_parser::convert(start_), sl@0: as_parser::convert(expr_), sl@0: as_parser::convert(end_) sl@0: ); sl@0: } sl@0: sl@0: // Generic generator function for creation of concrete confix parsers sl@0: // which have an action directly attached to the ExprT part of the sl@0: // parser (see comment above, no automatic refactoring) sl@0: sl@0: template sl@0: struct direct_result_type sl@0: { sl@0: typedef confix_parser< sl@0: typename as_parser::type, sl@0: typename as_parser::type, sl@0: typename as_parser::type, sl@0: plain_parser_category, // do not re-attach action sl@0: NestedT, sl@0: LexemeT sl@0: > type; sl@0: }; sl@0: sl@0: template sl@0: typename direct_result_type::type sl@0: direct(StartT const &start_, ExprT const &expr_, EndT const &end_) const sl@0: { sl@0: typedef typename direct_result_type::type sl@0: return_t; sl@0: sl@0: return return_t( sl@0: as_parser::convert(start_), sl@0: as_parser::convert(expr_), sl@0: as_parser::convert(end_) sl@0: ); sl@0: } sl@0: }; sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: // sl@0: // Predefined non_nested confix parser generators sl@0: // sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: const confix_parser_gen confix_p = sl@0: confix_parser_gen(); sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: // sl@0: // Comments are special types of confix parsers sl@0: // sl@0: // Comment parser generator template. This is a helper for generating a sl@0: // correct confix_parser<> from auxiliary parameters, which is able to sl@0: // parse comment constructs: (StartToken >> Comment text >> EndToken). sl@0: // sl@0: // There are the following types supported as parameters yet: parsers, sl@0: // single characters and strings (see as_parser). sl@0: // sl@0: // There are two diffenerent predefined comment parser generators sl@0: // (comment_p and comment_nest_p, see below), which may be used for sl@0: // creating special comment parsers in two different ways. sl@0: // sl@0: // If these are used with one parameter, a comment starting with the given sl@0: // first parser parameter up to the end of the line is matched. So for sl@0: // instance the following parser matches C++ style comments: sl@0: // sl@0: // comment_p("//"). sl@0: // sl@0: // If these are used with two parameters, a comment starting with the sl@0: // first parser parameter up to the second parser parameter is matched. sl@0: // For instance a C style comment parser should be constrcuted as: sl@0: // sl@0: // comment_p("/*", "*/"). sl@0: // sl@0: // Please note, that a comment is parsed implicitly as if the whole sl@0: // comment_p(...) statement were embedded into a lexeme_d[] directive. sl@0: // sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: template sl@0: struct comment_parser_gen sl@0: { sl@0: // Generic generator function for creation of concrete comment parsers sl@0: // from an open token. The newline parser eol_p is used as the sl@0: // closing token. sl@0: sl@0: template sl@0: struct paren_op1_result_type sl@0: { sl@0: typedef confix_parser< sl@0: typename as_parser::type, sl@0: kleene_star, sl@0: alternative, sl@0: unary_parser_category, // there is no action to re-attach sl@0: NestedT, sl@0: is_lexeme // insert implicit lexeme_d[] sl@0: > sl@0: type; sl@0: }; sl@0: sl@0: template sl@0: typename paren_op1_result_type::type sl@0: operator() (StartT const &start_) const sl@0: { sl@0: typedef typename paren_op1_result_type::type sl@0: return_t; sl@0: sl@0: return return_t( sl@0: as_parser::convert(start_), sl@0: *anychar_p, sl@0: eol_p | end_p sl@0: ); sl@0: } sl@0: sl@0: // Generic generator function for creation of concrete comment parsers sl@0: // from an open and a close tokens. sl@0: sl@0: template sl@0: struct paren_op2_result_type sl@0: { sl@0: typedef confix_parser< sl@0: typename as_parser::type, sl@0: kleene_star, sl@0: typename as_parser::type, sl@0: unary_parser_category, // there is no action to re-attach sl@0: NestedT, sl@0: is_lexeme // insert implicit lexeme_d[] sl@0: > type; sl@0: }; sl@0: sl@0: template sl@0: typename paren_op2_result_type::type sl@0: operator() (StartT const &start_, EndT const &end_) const sl@0: { sl@0: typedef typename paren_op2_result_type::type sl@0: return_t; sl@0: sl@0: return return_t( sl@0: as_parser::convert(start_), sl@0: *anychar_p, sl@0: as_parser::convert(end_) sl@0: ); sl@0: } sl@0: }; sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: // sl@0: // Predefined non_nested comment parser generator sl@0: // sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: const comment_parser_gen comment_p = sl@0: comment_parser_gen(); sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: // sl@0: // comment_nest_parser class sl@0: // sl@0: // Parses a nested comments. sl@0: // Example: nested PASCAL-comments: sl@0: // sl@0: // { This is a { nested } PASCAL-comment } sl@0: // sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: template sl@0: struct comment_nest_parser: sl@0: public parser > sl@0: { sl@0: typedef comment_nest_parser self_t; sl@0: sl@0: comment_nest_parser(OpenT const &open_, CloseT const &close_): sl@0: open(open_), close(close_) sl@0: {} sl@0: sl@0: template sl@0: typename parser_result::type sl@0: parse(ScannerT const &scan) const sl@0: { sl@0: return do_parse( sl@0: open >> *(*this | (anychar_p - close)) >> close, sl@0: scan); sl@0: } sl@0: sl@0: private: sl@0: template sl@0: typename parser_result::type sl@0: do_parse(ParserT const &p, ScannerT const &scan) const sl@0: { sl@0: return sl@0: impl::contiguous_parser_parse< sl@0: typename parser_result::type sl@0: >(p, scan, scan); sl@0: } sl@0: sl@0: typename as_parser::type::embed_t open; sl@0: typename as_parser::type::embed_t close; sl@0: }; sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: // sl@0: // Predefined nested comment parser generator sl@0: // sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: template sl@0: struct comment_nest_p_result sl@0: { sl@0: typedef comment_nest_parser< sl@0: typename as_parser::type, sl@0: typename as_parser::type sl@0: > type; sl@0: }; sl@0: sl@0: template sl@0: inline typename comment_nest_p_result::type sl@0: comment_nest_p(OpenT const &open, CloseT const &close) sl@0: { sl@0: typedef typename comment_nest_p_result::type sl@0: result_t; sl@0: sl@0: return result_t( sl@0: as_parser::convert(open), sl@0: as_parser::convert(close) sl@0: ); sl@0: } sl@0: sl@0: /////////////////////////////////////////////////////////////////////////////// sl@0: }} // namespace boost::spirit sl@0: sl@0: #endif