/*=============================================================================
    Boost.Wave: A Standard compliant C++ preprocessor library

    http://www.boost.org/

    Copyright (c) 2001-2012 Hartmut Kaiser. 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)
=============================================================================*/

#if !defined(CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED)
#define CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED

#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_parse_tree.hpp>
#include <boost/spirit/include/classic_parse_tree_utils.hpp>
#include <boost/spirit/include/classic_confix.hpp>
#include <boost/spirit/include/classic_lists.hpp>

#include <boost/wave/wave_config.hpp>
#include <boost/pool/pool_alloc.hpp>

#if BOOST_WAVE_DUMP_PARSE_TREE != 0
#include <map>
#include <boost/spirit/include/classic_tree_to_xml.hpp>
#endif

#include <boost/wave/token_ids.hpp>
#include <boost/wave/grammars/cpp_grammar_gen.hpp>
#include <boost/wave/util/pattern_parser.hpp>

#include <boost/wave/cpp_exceptions.hpp>

// this must occur after all of the includes and before any code appears
#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_PREFIX
#endif

///////////////////////////////////////////////////////////////////////////////
namespace boost {
namespace wave {
namespace grammars {

namespace impl {

///////////////////////////////////////////////////////////////////////////////
//
//  store_found_eof
//
//      The store_found_eof functor sets a given flag if the T_EOF token was
//      found during the parsing process
//
///////////////////////////////////////////////////////////////////////////////

    struct store_found_eof {

        store_found_eof(bool &found_eof_) : found_eof(found_eof_) {}

        template <typename TokenT>
        void operator()(TokenT const &/*token*/) const
        {
            found_eof = true;
        }

        bool &found_eof;
    };

///////////////////////////////////////////////////////////////////////////////
//
//  store_found_directive
//
//      The store_found_directive functor stores the token_id of the recognized
//      pp directive
//
///////////////////////////////////////////////////////////////////////////////

    template <typename TokenT>
    struct store_found_directive {

        store_found_directive(TokenT &found_directive_)
        :   found_directive(found_directive_) {}

        void operator()(TokenT const &token) const
        {
            found_directive = token;
        }

        TokenT &found_directive;
    };

///////////////////////////////////////////////////////////////////////////////
//
//  store_found_eoltokens
//
//      The store_found_eoltokens functor stores the token sequence of the
//      line ending for a particular pp directive
//
///////////////////////////////////////////////////////////////////////////////

    template <typename ContainerT>
    struct store_found_eoltokens {

        store_found_eoltokens(ContainerT &found_eoltokens_)
        :   found_eoltokens(found_eoltokens_) {}

        template <typename IteratorT>
        void operator()(IteratorT const &first, IteratorT const& last) const
        {
            std::copy(first, last,
                std::inserter(found_eoltokens, found_eoltokens.end()));
        }

        ContainerT &found_eoltokens;
    };

///////////////////////////////////////////////////////////////////////////////
//
//  flush_underlying_parser
//
//      The flush_underlying_parser flushes the underlying
//      multi_pass_iterator during the normal parsing process. This is
//      used at certain points during the parsing process, when it is
//      clear, that no backtracking is needed anymore and the input
//      gathered so far may be discarded.
//
///////////////////////////////////////////////////////////////////////////////
    struct flush_underlying_parser
    :   public boost::spirit::classic::parser<flush_underlying_parser>
    {
        typedef flush_underlying_parser this_t;

        template <typename ScannerT>
        typename boost::spirit::classic::parser_result<this_t, ScannerT>::type
        parse(ScannerT const& scan) const
        {
            scan.first.clear_queue();
            return scan.empty_match();
        }
    };

    flush_underlying_parser const
        flush_underlying_parser_p = flush_underlying_parser();

}   // anonymous namespace

///////////////////////////////////////////////////////////////////////////////
//  define, whether the rule's should generate some debug output
#define TRACE_CPP_GRAMMAR \
    bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR) \
    /**/

///////////////////////////////////////////////////////////////////////////////
// Encapsulation of the C++ preprocessor grammar.
template <typename TokenT, typename ContainerT>
struct cpp_grammar :
    public boost::spirit::classic::grammar<cpp_grammar<TokenT, ContainerT> >
{
    typedef typename TokenT::position_type  position_type;
    typedef cpp_grammar<TokenT, ContainerT> grammar_type;
    typedef impl::store_found_eof           store_found_eof_type;
    typedef impl::store_found_directive<TokenT>     store_found_directive_type;
    typedef impl::store_found_eoltokens<ContainerT> store_found_eoltokens_type;

    template <typename ScannerT>
    struct definition
    {
    // non-parse_tree generating rule type
        typedef typename ScannerT::iteration_policy_t iteration_policy_t;
        typedef boost::spirit::classic::match_policy match_policy_t;
        typedef typename ScannerT::action_policy_t action_policy_t;
        typedef
            boost::spirit::classic::scanner_policies<
                iteration_policy_t, match_policy_t, action_policy_t>
            policies_t;
        typedef
            boost::spirit::classic::scanner<typename ScannerT::iterator_t, policies_t>
            non_tree_scanner_t;
        typedef
            boost::spirit::classic::rule<
                non_tree_scanner_t, boost::spirit::classic::dynamic_parser_tag>
            no_tree_rule_type;

    // 'normal' (parse_tree generating) rule type
        typedef
            boost::spirit::classic::rule<
                ScannerT, boost::spirit::classic::dynamic_parser_tag>
            rule_type;

        rule_type pp_statement, macro_include_file;
//         rule_type include_file, system_include_file;
        rule_type plain_define, macro_definition, macro_parameters;
        rule_type undefine;
        rule_type ppifdef, ppifndef, ppif, ppelif;
//         rule_type ppelse, ppendif;
        rule_type ppline;
        rule_type pperror;
        rule_type ppwarning;
        rule_type pppragma;
        rule_type illformed;
        rule_type ppqualifiedname;
        rule_type eol_tokens;
        no_tree_rule_type ppsp;
#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
        rule_type ppregion;
        rule_type ppendregion;
#endif

        definition(cpp_grammar const &self)
        {
        // import the spirit and cpplexer namespaces here
            using namespace boost::spirit::classic;
            using namespace boost::wave;
            using namespace boost::wave::util;

        // set the rule id's for later use
            pp_statement.set_id(BOOST_WAVE_PP_STATEMENT_ID);
//             include_file.set_id(BOOST_WAVE_INCLUDE_FILE_ID);
//             system_include_file.set_id(BOOST_WAVE_SYSINCLUDE_FILE_ID);
            macro_include_file.set_id(BOOST_WAVE_MACROINCLUDE_FILE_ID);
            plain_define.set_id(BOOST_WAVE_PLAIN_DEFINE_ID);
            macro_parameters.set_id(BOOST_WAVE_MACRO_PARAMETERS_ID);
            macro_definition.set_id(BOOST_WAVE_MACRO_DEFINITION_ID);
            undefine.set_id(BOOST_WAVE_UNDEFINE_ID);
            ppifdef.set_id(BOOST_WAVE_IFDEF_ID);
            ppifndef.set_id(BOOST_WAVE_IFNDEF_ID);
            ppif.set_id(BOOST_WAVE_IF_ID);
            ppelif.set_id(BOOST_WAVE_ELIF_ID);
//             ppelse.set_id(BOOST_WAVE_ELSE_ID);
//             ppendif.set_id(BOOST_WAVE_ENDIF_ID);
            ppline.set_id(BOOST_WAVE_LINE_ID);
            pperror.set_id(BOOST_WAVE_ERROR_ID);
            ppwarning.set_id(BOOST_WAVE_WARNING_ID);
            pppragma.set_id(BOOST_WAVE_PRAGMA_ID);
            illformed.set_id(BOOST_WAVE_ILLFORMED_ID);
            ppsp.set_id(BOOST_WAVE_PPSPACE_ID);
            ppqualifiedname.set_id(BOOST_WAVE_PPQUALIFIEDNAME_ID);
#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
            ppregion.set_id(BOOST_WAVE_REGION_ID);
            ppendregion.set_id(BOOST_WAVE_ENDREGION_ID);
#endif

#if BOOST_WAVE_DUMP_PARSE_TREE != 0
            self.map_rule_id_to_name.init_rule_id_to_name_map(self);
#endif

        // recognizes preprocessor directives only

        // C++ standard 16.1: A preprocessing directive consists of a sequence
        // of preprocessing tokens. The first token in the sequence is #
        // preprocessing token that is either the first character in the source
        // file (optionally after white space containing no new-line
        // characters) or that follows white space containing at least one
        // new-line character. The last token in the sequence is the first
        // new-line character that follows the first token in the sequence.

            pp_statement
                =   (   plain_define
//                     |   include_file
//                     |   system_include_file
                    |   ppif
                    |   ppelif
                    |   ppifndef
                    |   ppifdef
                    |   undefine
//                     |   ppelse
                    |   macro_include_file
                    |   ppline
                    |   pppragma
                    |   pperror
                    |   ppwarning
//                     |   ppendif
#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
                    |   ppregion
                    |   ppendregion
#endif
                    |   illformed
                    )
                    >> eol_tokens
                       [ store_found_eoltokens_type(self.found_eoltokens) ]
//  In parser debug mode it is useful not to flush the underlying stream
//  to allow its investigation in the debugger and to see the correct
//  output in the printed debug log..
//  Note: this may break the parser, though.
#if !(defined(BOOST_SPIRIT_DEBUG) && \
      (BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR) \
     )
                   >>  impl::flush_underlying_parser_p
#endif // !(defined(BOOST_SPIRIT_DEBUG) &&
                ;

//         // #include ...
//             include_file            // include "..."
//                 =   ch_p(T_PP_QHEADER)
//                     [ store_found_directive_type(self.found_directive) ]
// #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
//                 |   ch_p(T_PP_QHEADER_NEXT)
//                     [ store_found_directive_type(self.found_directive) ]
// #endif
//                 ;

//             system_include_file     // include <...>
//                 =   ch_p(T_PP_HHEADER)
//                     [ store_found_directive_type(self.found_directive) ]
// #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
//                 |   ch_p(T_PP_HHEADER_NEXT)
//                     [ store_found_directive_type(self.found_directive) ]
// #endif
//                 ;

            macro_include_file      // include ...anything else...
                =   no_node_d
                    [
                        ch_p(T_PP_INCLUDE)
                        [ store_found_directive_type(self.found_directive) ]
#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
                    |   ch_p(T_PP_INCLUDE_NEXT)
                        [ store_found_directive_type(self.found_directive) ]
#endif
                    ]
                    >> *(   anychar_p -
                            (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
                        )
                ;

        // #define FOO foo (with optional parameters)
            plain_define
                =   no_node_d
                    [
                        ch_p(T_PP_DEFINE)
                        [ store_found_directive_type(self.found_directive) ]
                        >> +ppsp
                    ]
                    >>  (   ch_p(T_IDENTIFIER)
                        |   pattern_p(KeywordTokenType,
                                TokenTypeMask|PPTokenFlag)
                        |   pattern_p(OperatorTokenType|AltExtTokenType,
                                ExtTokenTypeMask|PPTokenFlag)   // and, bit_and etc.
                        |   pattern_p(BoolLiteralTokenType,
                                TokenTypeMask|PPTokenFlag)  // true/false
                        )
                    >>  (   (   no_node_d[eps_p(ch_p(T_LEFTPAREN))]
                                >>  macro_parameters
                                >> !macro_definition
                            )
                        |  !(   no_node_d[+ppsp]
                                >>  macro_definition
                            )
                        )
                ;

        // parameter list
        // normal C++ mode
            macro_parameters
                =   confix_p(
                        no_node_d[ch_p(T_LEFTPAREN) >> *ppsp],
                       !list_p(
                            (   ch_p(T_IDENTIFIER)
                            |   pattern_p(KeywordTokenType,
                                    TokenTypeMask|PPTokenFlag)
                            |   pattern_p(OperatorTokenType|AltExtTokenType,
                                    ExtTokenTypeMask|PPTokenFlag)   // and, bit_and etc.
                            |   pattern_p(BoolLiteralTokenType,
                                    TokenTypeMask|PPTokenFlag)  // true/false
#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
                            |   ch_p(T_ELLIPSIS)
#endif
                            ),
                            no_node_d[*ppsp >> ch_p(T_COMMA) >> *ppsp]
                        ),
                        no_node_d[*ppsp >> ch_p(T_RIGHTPAREN)]
                    )
                ;

        // macro body (anything left until eol)
            macro_definition
                =   no_node_d[*ppsp]
                    >> *(   anychar_p -
                            (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
                        )
                ;

        // #undef FOO
            undefine
                =   no_node_d
                    [
                        ch_p(T_PP_UNDEF)
                        [ store_found_directive_type(self.found_directive) ]
                        >> +ppsp
                    ]
                    >>  (   ch_p(T_IDENTIFIER)
                        |   pattern_p(KeywordTokenType,
                                TokenTypeMask|PPTokenFlag)
                        |   pattern_p(OperatorTokenType|AltExtTokenType,
                                ExtTokenTypeMask|PPTokenFlag)   // and, bit_and etc.
                        |   pattern_p(BoolLiteralTokenType,
                                TokenTypeMask|PPTokenFlag)  // true/false
                        )
                ;

        // #ifdef et.al.
            ppifdef
                =   no_node_d
                    [
                        ch_p(T_PP_IFDEF)
                        [ store_found_directive_type(self.found_directive) ]
                        >> +ppsp
                    ]
                    >>  ppqualifiedname
                ;

            ppifndef
                =   no_node_d
                    [
                        ch_p(T_PP_IFNDEF)
                        [ store_found_directive_type(self.found_directive) ]
                        >> +ppsp
                    ]
                    >>  ppqualifiedname
                ;

            ppif
                =   no_node_d
                    [
                        ch_p(T_PP_IF)
                        [ store_found_directive_type(self.found_directive) ]
//                        >> *ppsp
                    ]
                    >> +(   anychar_p -
                            (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
                        )
                ;

//             ppelse
//                 =   no_node_d
//                     [
//                         ch_p(T_PP_ELSE)
//                         [ store_found_directive_type(self.found_directive) ]
//                     ]
//                 ;

            ppelif
                =   no_node_d
                    [
                        ch_p(T_PP_ELIF)
                        [ store_found_directive_type(self.found_directive) ]
//                        >> *ppsp
                    ]
                    >> +(   anychar_p -
                            (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
                        )
                ;

//             ppendif
//                 =   no_node_d
//                     [
//                         ch_p(T_PP_ENDIF)
//                         [ store_found_directive_type(self.found_directive) ]
//                     ]
//                 ;

        // #line ...
            ppline
                =   no_node_d
                    [
                        ch_p(T_PP_LINE)
                        [ store_found_directive_type(self.found_directive) ]
                        >> *ppsp
                    ]
                    >> +(   anychar_p -
                            (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
                        )
                ;

#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
        // #region ...
            ppregion
                =   no_node_d
                    [
                        ch_p(T_MSEXT_PP_REGION)
                        [ store_found_directive_type(self.found_directive) ]
                        >> +ppsp
                    ]
                    >>  ppqualifiedname
                ;

        // #endregion
            ppendregion
                =   no_node_d
                    [
                        ch_p(T_MSEXT_PP_ENDREGION)
                        [ store_found_directive_type(self.found_directive) ]
                    ]
                ;
#endif

        // # something else (ill formed preprocessor directive)
            illformed           // for error reporting
                =   no_node_d
                    [
                        pattern_p(T_POUND, MainTokenMask)
                        >> *ppsp
                    ]
                    >>  (   anychar_p -
                            (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
                        )
                    >>  no_node_d
                        [
                           *(   anychar_p -
                                (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
                            )
                        ]
                ;

        // #error
            pperror
                =   no_node_d
                    [
                        ch_p(T_PP_ERROR)
                        [ store_found_directive_type(self.found_directive) ]
                        >> *ppsp
                    ]
                    >> *(   anychar_p -
                            (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
                        )
                ;

        // #warning
            ppwarning
                =   no_node_d
                    [
                        ch_p(T_PP_WARNING)
                        [ store_found_directive_type(self.found_directive) ]
                        >> *ppsp
                    ]
                    >> *(   anychar_p -
                            (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
                        )
                ;

        // #pragma ...
            pppragma
                =   no_node_d
                    [
                        ch_p(T_PP_PRAGMA)
                        [ store_found_directive_type(self.found_directive) ]
                    ]
                    >> *(   anychar_p -
                            (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
                        )
                ;

            ppqualifiedname
                =   no_node_d[*ppsp]
                    >>  (   ch_p(T_IDENTIFIER)
                        |   pattern_p(KeywordTokenType,
                                TokenTypeMask|PPTokenFlag)
                        |   pattern_p(OperatorTokenType|AltExtTokenType,
                                ExtTokenTypeMask|PPTokenFlag)   // and, bit_and etc.
                        |   pattern_p(BoolLiteralTokenType,
                                TokenTypeMask|PPTokenFlag)  // true/false
                        )
                ;

        // auxiliary helper rules
            ppsp     // valid space in a line with a preprocessor directive
                =   ch_p(T_SPACE) | ch_p(T_CCOMMENT)
                ;

        // end of line tokens
            eol_tokens
                =   no_node_d
                    [
                       *(   ch_p(T_SPACE)
                        |   ch_p(T_CCOMMENT)
                        )
                    >>  (   ch_p(T_NEWLINE)
                        |   ch_p(T_CPPCOMMENT)
                        |   ch_p(T_EOF)
                            [ store_found_eof_type(self.found_eof) ]
                        )
                    ]
                ;

            BOOST_SPIRIT_DEBUG_TRACE_RULE(pp_statement, TRACE_CPP_GRAMMAR);
//             BOOST_SPIRIT_DEBUG_TRACE_RULE(include_file, TRACE_CPP_GRAMMAR);
//             BOOST_SPIRIT_DEBUG_TRACE_RULE(system_include_file, TRACE_CPP_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_include_file, TRACE_CPP_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(plain_define, TRACE_CPP_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_definition, TRACE_CPP_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_parameters, TRACE_CPP_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(undefine, TRACE_CPP_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(ppifdef, TRACE_CPP_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(ppifndef, TRACE_CPP_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(ppif, TRACE_CPP_GRAMMAR);
//             BOOST_SPIRIT_DEBUG_TRACE_RULE(ppelse, TRACE_CPP_GRAMMAR);
//             BOOST_SPIRIT_DEBUG_TRACE_RULE(ppelif, TRACE_CPP_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(ppendif, TRACE_CPP_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(ppline, TRACE_CPP_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(pperror, TRACE_CPP_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(ppwarning, TRACE_CPP_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(illformed, TRACE_CPP_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(ppsp, TRACE_CPP_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(ppqualifiedname, TRACE_CPP_GRAMMAR);
#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
            BOOST_SPIRIT_DEBUG_TRACE_RULE(ppregion, TRACE_CPP_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(ppendregion, TRACE_CPP_GRAMMAR);
#endif
        }

    // start rule of this grammar
        rule_type const& start() const
        { return pp_statement; }
    };

    bool &found_eof;
    TokenT &found_directive;
    ContainerT &found_eoltokens;

    cpp_grammar(bool &found_eof_, TokenT &found_directive_,
            ContainerT &found_eoltokens_)
    :   found_eof(found_eof_),
        found_directive(found_directive_),
        found_eoltokens(found_eoltokens_)
    {
        BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "cpp_grammar",
            TRACE_CPP_GRAMMAR);
    }

#if BOOST_WAVE_DUMP_PARSE_TREE != 0
// helper function and data to get readable names of the rules known to us
    struct map_ruleid_to_name :
        public std::map<boost::spirit::classic::parser_id, std::string>
    {
        typedef std::map<boost::spirit::classic::parser_id, std::string> base_type;

        void init_rule_id_to_name_map(cpp_grammar const &self)
        {
            struct {
                int parser_id;
                char const *rule_name;
            }
            init_ruleid_name_map[] = {
                { BOOST_WAVE_PP_STATEMENT_ID, "pp_statement" },
//                 { BOOST_WAVE_INCLUDE_FILE_ID, "include_file" },
//                 { BOOST_WAVE_SYSINCLUDE_FILE_ID, "system_include_file" },
                { BOOST_WAVE_MACROINCLUDE_FILE_ID, "macro_include_file" },
                { BOOST_WAVE_PLAIN_DEFINE_ID, "plain_define" },
                { BOOST_WAVE_MACRO_PARAMETERS_ID, "macro_parameters" },
                { BOOST_WAVE_MACRO_DEFINITION_ID, "macro_definition" },
                { BOOST_WAVE_UNDEFINE_ID, "undefine" },
                { BOOST_WAVE_IFDEF_ID, "ppifdef" },
                { BOOST_WAVE_IFNDEF_ID, "ppifndef" },
                { BOOST_WAVE_IF_ID, "ppif" },
                { BOOST_WAVE_ELIF_ID, "ppelif" },
//                 { BOOST_WAVE_ELSE_ID, "ppelse" },
//                 { BOOST_WAVE_ENDIF_ID, "ppendif" },
                { BOOST_WAVE_LINE_ID, "ppline" },
                { BOOST_WAVE_ERROR_ID, "pperror" },
                { BOOST_WAVE_WARNING_ID, "ppwarning" },
                { BOOST_WAVE_PRAGMA_ID, "pppragma" },
                { BOOST_WAVE_ILLFORMED_ID, "illformed" },
                { BOOST_WAVE_PPSPACE_ID, "ppspace" },
                { BOOST_WAVE_PPQUALIFIEDNAME_ID, "ppqualifiedname" },
#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
                { BOOST_WAVE_REGION_ID, "ppregion" },
                { BOOST_WAVE_ENDREGION_ID, "ppendregion" },
#endif
                { 0 }
            };

        // initialize parser_id to rule_name map
            for (int i = 0; 0 != init_ruleid_name_map[i].parser_id; ++i)
                base_type::insert(base_type::value_type(
                    boost::spirit::classic::parser_id(init_ruleid_name_map[i].parser_id),
                    std::string(init_ruleid_name_map[i].rule_name))
                );
        }
    };
    mutable map_ruleid_to_name map_rule_id_to_name;
#endif // WAVE_DUMP_PARSE_TREE != 0
};

///////////////////////////////////////////////////////////////////////////////
#undef TRACE_CPP_GRAMMAR

///////////////////////////////////////////////////////////////////////////////
//
//  Special parse function generating a parse tree using a given node_factory.
//
///////////////////////////////////////////////////////////////////////////////
template <typename NodeFactoryT, typename IteratorT, typename ParserT>
inline boost::spirit::classic::tree_parse_info<IteratorT, NodeFactoryT>
parsetree_parse(IteratorT const& first_, IteratorT const& last,
    boost::spirit::classic::parser<ParserT> const& p)
{
    using namespace boost::spirit::classic;

    typedef pt_match_policy<IteratorT, NodeFactoryT> pt_match_policy_type;
    typedef scanner_policies<iteration_policy, pt_match_policy_type>
        scanner_policies_type;
    typedef scanner<IteratorT, scanner_policies_type> scanner_type;

    scanner_policies_type policies;
    IteratorT first = first_;
    scanner_type scan(first, last, policies);
    tree_match<IteratorT, NodeFactoryT> hit = p.derived().parse(scan);
    return tree_parse_info<IteratorT, NodeFactoryT>(
        first, hit, hit && (first == last), hit.length(), hit.trees);
}

///////////////////////////////////////////////////////////////////////////////
//
//  The following parse function is defined here, to allow the separation of
//  the compilation of the cpp_grammar from the function using it.
//
///////////////////////////////////////////////////////////////////////////////

#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0
#define BOOST_WAVE_GRAMMAR_GEN_INLINE
#else
#define BOOST_WAVE_GRAMMAR_GEN_INLINE inline
#endif

template <typename LexIteratorT, typename TokenContainerT>
BOOST_WAVE_GRAMMAR_GEN_INLINE
boost::spirit::classic::tree_parse_info<
    LexIteratorT,
    typename cpp_grammar_gen<LexIteratorT, TokenContainerT>::node_factory_type
>
cpp_grammar_gen<LexIteratorT, TokenContainerT>::parse_cpp_grammar (
    LexIteratorT const &first, LexIteratorT const &last,
    position_type const &act_pos, bool &found_eof,
    token_type &found_directive, token_container_type &found_eoltokens)
{
    using namespace boost::spirit::classic;
    using namespace boost::wave;

    cpp_grammar<token_type, TokenContainerT> g(found_eof, found_directive, found_eoltokens);
    tree_parse_info<LexIteratorT, node_factory_type> hit =
        parsetree_parse<node_factory_type>(first, last, g);

#if BOOST_WAVE_DUMP_PARSE_TREE != 0
    if (hit.match) {
        tree_to_xml (BOOST_WAVE_DUMP_PARSE_TREE_OUT, hit.trees, "",
            g.map_rule_id_to_name, &token_type::get_token_id,
            &token_type::get_token_value);
    }
#endif

    return hit;
}

#undef BOOST_WAVE_GRAMMAR_GEN_INLINE

///////////////////////////////////////////////////////////////////////////////
}   // namespace grammars
}   // namespace wave
}   // namespace boost

// the suffix header occurs after all of the code
#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif

#endif // !defined(CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED)
