| /*============================================================================= |
| 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 |