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