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

    http://www.boost.org/

    Copyright (c) 2001-2010 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_PREDEF_MACROS_GRAMMAR_HPP_53858C9A_C202_4D60_AD92_DC9CAE4DBB43_INCLUDED)
#define CPP_PREDEF_MACROS_GRAMMAR_HPP_53858C9A_C202_4D60_AD92_DC9CAE4DBB43_INCLUDED

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

#include <boost/wave/wave_config.hpp>
#include <boost/wave/token_ids.hpp>
#include <boost/wave/grammars/cpp_predef_macros_gen.hpp>
#include <boost/wave/util/pattern_parser.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 {

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

///////////////////////////////////////////////////////////////////////////////
// Encapsulation of the grammar for command line driven predefined macros.
struct predefined_macros_grammar : 
    public boost::spirit::classic::grammar<predefined_macros_grammar>
{
    template <typename ScannerT>
    struct definition
    {
    // 'normal' (parse_tree generating) rule type
        typedef boost::spirit::classic::rule<
                ScannerT, boost::spirit::classic::dynamic_parser_tag> 
            rule_type;

        rule_type plain_define, macro_definition, macro_parameters;

        definition(predefined_macros_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
            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);

        // recognizes command line defined macro syntax, i.e.
        //  -DMACRO
        //  -DMACRO=
        //  -DMACRO=value
        //  -DMACRO(x)
        //  -DMACRO(x)=
        //  -DMACRO(x)=value

        // This grammar resembles the overall structure of the cpp_grammar to
        // make it possible to reuse the parse tree traversal code
            plain_define
                =   (   ch_p(T_IDENTIFIER)
                    |   pattern_p(KeywordTokenType, TokenTypeMask)
                    |   pattern_p(OperatorTokenType|AltExtTokenType, 
                            ExtTokenTypeMask)   // and, bit_and etc.
                    |   pattern_p(BoolLiteralTokenType, TokenTypeMask)  // true/false
                    )
                    >>  !macro_parameters
                    >>  !macro_definition
                ;

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

        // macro body (anything left until eol)
            macro_definition
                =   no_node_d[ch_p(T_ASSIGN)]
                    >> *anychar_p
                ;

            BOOST_SPIRIT_DEBUG_TRACE_RULE(plain_define, TRACE_PREDEF_MACROS_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_definition, TRACE_PREDEF_MACROS_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_parameters, TRACE_PREDEF_MACROS_GRAMMAR);
        }

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

    predefined_macros_grammar() 
    { 
        BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, 
            "predefined_macros_grammar", TRACE_PREDEF_MACROS_GRAMMAR); 
    }

};

///////////////////////////////////////////////////////////////////////////////
#undef TRACE_PREDEF_MACROS_GRAMMAR

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

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

template <typename LexIteratorT>
BOOST_WAVE_PREDEF_MACROS_GRAMMAR_GEN_INLINE 
boost::spirit::classic::tree_parse_info<LexIteratorT>
predefined_macros_grammar_gen<LexIteratorT>::parse_predefined_macro (
    LexIteratorT const &first, LexIteratorT const &last)
{
    predefined_macros_grammar g;
    return boost::spirit::classic::pt_parse (first, last, g);
}

#undef BOOST_WAVE_PREDEF_MACROS_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_PREDEF_MACROS_GRAMMAR_HPP_53858C9A_C202_4D60_AD92_DC9CAE4DBB43_INCLUDED)
