/*============================================================================= Copyright (c) 2002-2003 Hartmut Kaiser http://spirit.sourceforge.net/ Use, modification and distribution is subject to 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 #include #include #include /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace spirit { /////////////////////////////////////////////////////////////////////////////// // // 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 */ // /////////////////////////////////////////////////////////////////////////////// template struct confix_parser_gen; template < typename OpenT, typename ExprT, typename CloseT, typename CategoryT, typename NestedT = non_nested, typename LexemeT = non_lexeme > struct confix_parser : public parser< confix_parser > { typedef confix_parser self_t; confix_parser(OpenT const &open_, ExprT const &expr_, CloseT const &close_) : open(open_), expr(expr_), close(close_) {} template typename parser_result::type parse(ScannerT const& scan) const { return impl::confix_parser_type:: parse(NestedT(), LexemeT(), *this, scan, open, expr, close); } private: typename as_parser::type::embed_t open; typename as_parser::type::embed_t expr; typename as_parser::type::embed_t close; }; /////////////////////////////////////////////////////////////////////////////// // // 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 struct confix_parser_gen { // Generic generator function for creation of concrete confix parsers template confix_parser< typename as_parser::type, typename as_parser::type, typename as_parser::type, typename as_parser::type::parser_category_t, NestedT, LexemeT > operator()( StartT const &start_, ExprT const &expr_, EndT const &end_) const { typedef typename as_parser::type start_t; typedef typename as_parser::type expr_t; typedef typename as_parser::type end_t; typedef typename as_parser::type::parser_category_t parser_category_t; typedef confix_parser< start_t, expr_t, end_t, parser_category_t, NestedT, LexemeT > return_t; return return_t( as_parser::convert(start_), as_parser::convert(expr_), as_parser::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 confix_parser< typename as_parser::type, typename as_parser::type, typename as_parser::type, plain_parser_category, // do not re-attach action NestedT, LexemeT > direct(StartT const &start_, ExprT const &expr_, EndT const &end_) const { typedef typename as_parser::type start_t; typedef typename as_parser::type expr_t; typedef typename as_parser::type end_t; typedef plain_parser_category parser_category_t; typedef confix_parser< start_t, expr_t, end_t, parser_category_t, NestedT, LexemeT > return_t; return return_t( as_parser::convert(start_), as_parser::convert(expr_), as_parser::convert(end_) ); } }; /////////////////////////////////////////////////////////////////////////////// // // Predefined non_nested confix parser generators // /////////////////////////////////////////////////////////////////////////////// const confix_parser_gen confix_p = confix_parser_gen(); /////////////////////////////////////////////////////////////////////////////// // // 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 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 confix_parser< typename as_parser::type, kleene_star, alternative, unary_parser_category, // there is no action to re-attach NestedT, is_lexeme // insert implicit lexeme_d[] > operator() (StartT const &start_) const { typedef typename as_parser::type start_t; typedef kleene_star expr_t; typedef alternative end_t; typedef unary_parser_category parser_category_t; typedef confix_parser< start_t, expr_t, end_t, parser_category_t, NestedT, is_lexeme > return_t; return return_t( as_parser::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 confix_parser< typename as_parser::type, kleene_star, typename as_parser::type, unary_parser_category, // there is no action to re-attach NestedT, is_lexeme // insert implicit lexeme_d[] > operator() (StartT const &start_, EndT const &end_) const { typedef typename as_parser::type start_t; typedef kleene_star expr_t; typedef typename as_parser::type end_t; typedef unary_parser_category parser_category_t; typedef confix_parser< start_t, expr_t, end_t, parser_category_t, NestedT, is_lexeme > return_t; return return_t( as_parser::convert(start_), *anychar_p, as_parser::convert(end_) ); } }; /////////////////////////////////////////////////////////////////////////////// // // Predefined non_nested comment parser generator // /////////////////////////////////////////////////////////////////////////////// const comment_parser_gen comment_p = comment_parser_gen(); /////////////////////////////////////////////////////////////////////////////// // // comment_nest_parser class // // Parses a nested comments. // Example: nested PASCAL-comments: // // { This is a { nested } PASCAL-comment } // /////////////////////////////////////////////////////////////////////////////// template struct comment_nest_parser: public parser > { typedef comment_nest_parser self_t; comment_nest_parser(OpenT const &open_, CloseT const &close_): open(open_), close(close_) {} template typename parser_result::type parse(ScannerT const &scan) const { return do_parse( open >> *(*this | (anychar_p - close)) >> close, scan); } private: template typename parser_result::type do_parse(ParserT const &p, ScannerT const &scan) const { return impl::contiguous_parser_parse< BOOST_DEDUCED_TYPENAME parser_result::type >(p, scan, scan); } typename as_parser::type::embed_t open; typename as_parser::type::embed_t close; }; /////////////////////////////////////////////////////////////////////////////// // // Predefined nested comment parser generator // /////////////////////////////////////////////////////////////////////////////// template inline comment_nest_parser< typename as_parser::type, typename as_parser::type > comment_nest_p(OpenT const &open, CloseT const &close) { return comment_nest_parser< BOOST_DEDUCED_TYPENAME as_parser::type, BOOST_DEDUCED_TYPENAME as_parser::type >( as_parser::convert(open), as_parser::convert(close) ); } /////////////////////////////////////////////////////////////////////////////// }} // namespace boost::spirit #endif