/*=============================================================================
    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_EXPRESSION_GRAMMAR_HPP_099CD1A4_A6C0_44BE_8F24_0B00F5BE5674_INCLUDED)
#define CPP_EXPRESSION_GRAMMAR_HPP_099CD1A4_A6C0_44BE_8F24_0B00F5BE5674_INCLUDED

#include <boost/wave/wave_config.hpp>

#include <boost/assert.hpp>
#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_closure.hpp>
#include <boost/spirit/include/classic_if.hpp>
#include <boost/spirit/include/classic_assign_actor.hpp>
#include <boost/spirit/include/classic_push_back_actor.hpp>

#include <boost/spirit/include/phoenix1_functions.hpp>
#include <boost/spirit/include/phoenix1_operators.hpp>
#include <boost/spirit/include/phoenix1_primitives.hpp>
#include <boost/spirit/include/phoenix1_statements.hpp>
#include <boost/spirit/include/phoenix1_casts.hpp>

#include <boost/wave/token_ids.hpp>

#include <boost/wave/cpp_exceptions.hpp>
#include <boost/wave/grammars/cpp_expression_grammar_gen.hpp>   
#include <boost/wave/grammars/cpp_literal_grammar_gen.hpp>  
#include <boost/wave/grammars/cpp_expression_value.hpp>
#include <boost/wave/util/pattern_parser.hpp>
#include <boost/wave/util/macro_helpers.hpp>

#if !defined(spirit_append_actor)
#define spirit_append_actor(actor) boost::spirit::classic::push_back_a(actor)
#define spirit_assign_actor(actor) boost::spirit::classic::assign_a(actor)
#endif // !defined(spirit_append_actor)

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

///////////////////////////////////////////////////////////////////////////////
//
//  Encapsulation of the grammar for evaluation of constant preprocessor
//  expressions
//
///////////////////////////////////////////////////////////////////////////////
namespace boost {
namespace wave { 
namespace grammars {
namespace closures {

///////////////////////////////////////////////////////////////////////////////
//
//  define the closure type used throughout the C++ expression grammar
//
//      Throughout this grammar all literal tokens are stored into a 
//      closure_value variables, which converts the types appropriately, where 
//      required.
//
///////////////////////////////////////////////////////////////////////////////
    struct cpp_expr_closure 
    :   boost::spirit::classic::closure<cpp_expr_closure, closure_value> 
    {
        member1 val;
    };

}   // namespace closures

namespace impl {

///////////////////////////////////////////////////////////////////////////////
//
//  convert the given token value (integer literal) to a unsigned long
//
///////////////////////////////////////////////////////////////////////////////
    struct convert_intlit {

        template <typename ArgT>
        struct result { 
        
            typedef boost::wave::grammars::closures::closure_value type; 
        };

        template <typename TokenT>
        boost::wave::grammars::closures::closure_value 
        operator()(TokenT const &token) const
        { 
            typedef boost::wave::grammars::closures::closure_value return_type;
            bool is_unsigned = false;
            uint_literal_type ul = intlit_grammar_gen<TokenT>::evaluate(token, 
                is_unsigned);

            return is_unsigned ? 
                return_type(ul) : return_type(static_cast<int_literal_type>(ul));
        }
    };
    phoenix::function<convert_intlit> const as_intlit;

///////////////////////////////////////////////////////////////////////////////
//
//  convert the given token value (character literal) to a unsigned int
//
///////////////////////////////////////////////////////////////////////////////
    struct convert_chlit {

        template <typename ArgT>
        struct result { 
        
            typedef boost::wave::grammars::closures::closure_value type; 
        };

        template <typename TokenT>
        boost::wave::grammars::closures::closure_value 
        operator()(TokenT const &token) const
        { 
            typedef boost::wave::grammars::closures::closure_value return_type;
            value_error status = error_noerror;
            unsigned int value = chlit_grammar_gen<TokenT>::evaluate(token, status);
            return return_type(value, status);
        }
    };
    phoenix::function<convert_chlit> const as_chlit;

////////////////////////////////////////////////////////////////////////////////
//
//  Handle the ?: operator with correct type and error propagation
//
////////////////////////////////////////////////////////////////////////////////
    struct operator_questionmark {
    
        template <typename CondT, typename Arg1T, typename Arg2T>
        struct result { 
        
            typedef boost::wave::grammars::closures::closure_value type; 
        };

        template <typename CondT, typename Arg1T, typename Arg2T>
        boost::wave::grammars::closures::closure_value 
        operator()(CondT const &cond, Arg1T &val1, Arg2T const &val2) const
        { 
            return val1.handle_questionmark(cond, val2);
        }
    };
    phoenix::function<operator_questionmark> const questionmark;

///////////////////////////////////////////////////////////////////////////////
//
//  Handle type conversion conserving error conditions
//
///////////////////////////////////////////////////////////////////////////////
    struct operator_to_bool {
    
        template <typename ArgT>
        struct result { 
        
            typedef boost::wave::grammars::closures::closure_value type; 
        };

        template <typename ArgT>
        boost::wave::grammars::closures::closure_value 
        operator()(ArgT &val) const
        { 
            typedef boost::wave::grammars::closures::closure_value return_type;
            return return_type(
                boost::wave::grammars::closures::as_bool(val), val.is_valid());
        }
    };
    phoenix::function<operator_to_bool> const to_bool;
    
///////////////////////////////////////////////////////////////////////////////
//
//  Handle explicit type conversion
//
///////////////////////////////////////////////////////////////////////////////
    struct operator_as_bool {
    
        template <typename ArgT>
        struct result { 
        
            typedef bool type; 
        };

        template <typename ArgT>
        bool
        operator()(ArgT &val) const
        { 
            return boost::wave::grammars::closures::as_bool(val);
        }
    };
    phoenix::function<operator_as_bool> const as_bool;
    
///////////////////////////////////////////////////////////////////////////////
//
//  Handle closure value operators with proper error propagation
//
///////////////////////////////////////////////////////////////////////////////
#define BOOST_WAVE_BINARYOP(op, optok)                                        \
    struct operator_binary_ ## op {                                           \
                                                                              \
        template <typename Arg1T, typename Arg2T>                             \
        struct result {                                                       \
                                                                              \
            typedef boost::wave::grammars::closures::closure_value type;      \
        };                                                                    \
                                                                              \
        template <typename Arg1T, typename Arg2T>                             \
        boost::wave::grammars::closures::closure_value                        \
        operator()(Arg1T &val1, Arg2T &val2) const                            \
        {                                                                     \
            return val1 optok val2;                                           \
        }                                                                     \
    };                                                                        \
    phoenix::function<operator_binary_ ## op> const binary_ ## op             \
    /**/

    BOOST_WAVE_BINARYOP(and, &&);
    BOOST_WAVE_BINARYOP(or, ||);
    
    BOOST_WAVE_BINARYOP(bitand, &);
    BOOST_WAVE_BINARYOP(bitor, |);
    BOOST_WAVE_BINARYOP(bitxor, ^);
    
    BOOST_WAVE_BINARYOP(lesseq, <=);
    BOOST_WAVE_BINARYOP(less, <);
    BOOST_WAVE_BINARYOP(greater, >);
    BOOST_WAVE_BINARYOP(greateq, >=);
    BOOST_WAVE_BINARYOP(eq, ==);
    BOOST_WAVE_BINARYOP(ne, !=);

#undef BOOST_WAVE_BINARYOP

///////////////////////////////////////////////////////////////////////////////
#define BOOST_WAVE_UNARYOP(op, optok)                                         \
    struct operator_unary_ ## op {                                            \
                                                                              \
        template <typename ArgT>                                              \
        struct result {                                                       \
                                                                              \
            typedef boost::wave::grammars::closures::closure_value type;      \
        };                                                                    \
                                                                              \
        template <typename ArgT>                                              \
        boost::wave::grammars::closures::closure_value                        \
        operator()(ArgT &val) const                                           \
        {                                                                     \
            return optok val;                                                 \
        }                                                                     \
    };                                                                        \
    phoenix::function<operator_unary_ ## op> const unary_ ## op               \
    /**/

    BOOST_WAVE_UNARYOP(neg, !);
    
#undef BOOST_WAVE_UNARYOP

}   // namespace impl

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

struct expression_grammar :
    public boost::spirit::classic::grammar<
        expression_grammar, 
        closures::cpp_expr_closure::context_t
    >
{
    expression_grammar()
    {
        BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "expression_grammar", 
            TRACE_CPP_EXPR_GRAMMAR);
    }
    
    // no need for copy constructor/assignment operator
    expression_grammar(expression_grammar const&);
    expression_grammar& operator= (expression_grammar const&);
    
    template <typename ScannerT>
    struct definition
    {
        typedef closures::cpp_expr_closure closure_type;
        typedef boost::spirit::classic::rule<ScannerT, closure_type::context_t> rule_t;
        typedef boost::spirit::classic::rule<ScannerT> simple_rule_t;

        simple_rule_t pp_expression;
        
        rule_t const_exp;
        rule_t logical_or_exp, logical_and_exp;
        rule_t inclusive_or_exp, exclusive_or_exp, and_exp;
        rule_t cmp_equality, cmp_relational;
        rule_t shift_exp;
        rule_t add_exp, multiply_exp;
        rule_t unary_exp, primary_exp, constant;

        rule_t const_exp_nocalc;
        rule_t logical_or_exp_nocalc, logical_and_exp_nocalc;
        rule_t inclusive_or_exp_nocalc, exclusive_or_exp_nocalc, and_exp_nocalc;
        rule_t cmp_equality_nocalc, cmp_relational_nocalc;
        rule_t shift_exp_nocalc;
        rule_t add_exp_nocalc, multiply_exp_nocalc;
        rule_t unary_exp_nocalc, primary_exp_nocalc, constant_nocalc;

        boost::spirit::classic::subrule<0, closure_type::context_t> const_exp_subrule;

        definition(expression_grammar const &self)
        {
            using namespace boost::spirit::classic;
            using namespace phoenix;
            using namespace boost::wave;
            using boost::wave::util::pattern_p;
            
            pp_expression
                =   const_exp[self.val = arg1]
                ;
                
            const_exp
                =   logical_or_exp[const_exp.val = arg1]
                    >> !(const_exp_subrule =
                            ch_p(T_QUESTION_MARK)
                            >>  const_exp
                                [
                                    const_exp_subrule.val = arg1
                                ] 
                            >>  ch_p(T_COLON)
                            >>  const_exp
                                [
                                    const_exp_subrule.val = 
                                        impl::questionmark(const_exp.val, 
                                            const_exp_subrule.val, arg1)
                                ]
                        )[const_exp.val = arg1]
                ;

            logical_or_exp 
                =   logical_and_exp[logical_or_exp.val = arg1]
                    >> *(   if_p(impl::as_bool(logical_or_exp.val))
                            [
                                // if one of the || operators is true, no more
                                // evaluation is required
                                pattern_p(T_OROR, MainTokenMask)
                                >>  logical_and_exp_nocalc
                                    [
                                        logical_or_exp.val = 
                                            impl::to_bool(logical_or_exp.val)
                                    ]
                            ]
                            .else_p
                            [
                                pattern_p(T_OROR, MainTokenMask)
                                >>  logical_and_exp
                                    [
                                        logical_or_exp.val = 
                                            impl::binary_or(logical_or_exp.val, arg1)
                                    ]
                            ]
                        )
                ;

            logical_and_exp
                =   inclusive_or_exp[logical_and_exp.val = arg1]
                    >> *(   if_p(impl::as_bool(logical_and_exp.val))
                            [
                                pattern_p(T_ANDAND, MainTokenMask)
                                >>  inclusive_or_exp
                                    [
                                        logical_and_exp.val = 
                                            impl::binary_and(logical_and_exp.val, arg1)
                                    ]
                            ]
                            .else_p
                            [
                                // if one of the && operators is false, no more
                                // evaluation is required
                                pattern_p(T_ANDAND, MainTokenMask)
                                >>  inclusive_or_exp_nocalc
                                    [
                                        logical_and_exp.val =
                                            impl::to_bool(logical_and_exp.val)
                                    ]
                            ]
                        )
                ;

            inclusive_or_exp
                =   exclusive_or_exp[inclusive_or_exp.val = arg1]
                    >> *(   pattern_p(T_OR, MainTokenMask)
                            >>  exclusive_or_exp
                                [
                                    inclusive_or_exp.val = 
                                        impl::binary_bitor(inclusive_or_exp.val, arg1)
                                ]
                        )
                ;

            exclusive_or_exp
                =   and_exp[exclusive_or_exp.val = arg1]
                    >> *(   pattern_p(T_XOR, MainTokenMask)
                            >>  and_exp
                                [
                                    exclusive_or_exp.val = 
                                        impl::binary_bitxor(exclusive_or_exp.val, arg1)
                                ]
                        )
                ;

            and_exp
                =   cmp_equality[and_exp.val = arg1]
                    >> *(   pattern_p(T_AND, MainTokenMask)
                            >>  cmp_equality
                                [
                                    and_exp.val = 
                                        impl::binary_bitand(and_exp.val, arg1)
                                ]
                        )
                ;

            cmp_equality
                =   cmp_relational[cmp_equality.val = arg1]
                    >> *(   ch_p(T_EQUAL)
                            >>  cmp_relational
                                [
                                    cmp_equality.val = 
                                        impl::binary_eq(cmp_equality.val, arg1)
                                ]
                        |   pattern_p(T_NOTEQUAL, MainTokenMask)
                            >>  cmp_relational
                                [
                                    cmp_equality.val = 
                                        impl::binary_ne(cmp_equality.val, arg1)
                                ]
                        )
                ;

            cmp_relational
                =   shift_exp[cmp_relational.val = arg1]
                    >> *(   ch_p(T_LESSEQUAL)
                            >>  shift_exp
                                [
                                    cmp_relational.val = 
                                        impl::binary_lesseq(cmp_relational.val, arg1)
                                ]
                        |   ch_p(T_GREATEREQUAL)
                            >>  shift_exp
                                [
                                    cmp_relational.val = 
                                        impl::binary_greateq(cmp_relational.val, arg1)
                                ]
                        |   ch_p(T_LESS)
                            >>  shift_exp
                                [
                                    cmp_relational.val = 
                                        impl::binary_less(cmp_relational.val, arg1)
                                ]
                        |   ch_p(T_GREATER)
                            >>  shift_exp
                                [
                                    cmp_relational.val = 
                                        impl::binary_greater(cmp_relational.val, arg1)
                                ]
                        )
                ;

            shift_exp
                =   add_exp[shift_exp.val = arg1]
                    >> *(   ch_p(T_SHIFTLEFT)
                            >>  add_exp
                                [
                                    shift_exp.val <<= arg1
                                ]
                        |   ch_p(T_SHIFTRIGHT)
                            >>  add_exp
                                [
                                    shift_exp.val >>= arg1
                                ]
                        )
                ;

            add_exp
                =   multiply_exp[add_exp.val = arg1]
                    >> *(   ch_p(T_PLUS)
                            >>  multiply_exp
                                [
                                    add_exp.val += arg1
                                ]
                        |   ch_p(T_MINUS)
                            >>  multiply_exp
                                [
                                    add_exp.val -= arg1
                                ]
                        )
                ;

            multiply_exp
                =   unary_exp[multiply_exp.val = arg1]
                    >> *(   ch_p(T_STAR)
                            >>  unary_exp
                                [
                                    multiply_exp.val *= arg1
                                ]
                        |   ch_p(T_DIVIDE)
                            >>  unary_exp
                                [
                                    multiply_exp.val /= arg1
                                ]
                        |   ch_p(T_PERCENT)
                            >>  unary_exp
                                [
                                    multiply_exp.val %= arg1
                                ]
                        )
                ;

            unary_exp
                =   primary_exp[unary_exp.val = arg1]
                |   ch_p(T_PLUS) >> unary_exp
                    [
                        unary_exp.val = arg1
                    ]
                |   ch_p(T_MINUS) >> unary_exp
                    [
                        unary_exp.val = -arg1
                    ]
                |   pattern_p(T_COMPL, MainTokenMask) >> unary_exp
                    [
                        unary_exp.val = ~arg1
                    ]
                |   pattern_p(T_NOT, MainTokenMask) >> unary_exp
                    [
                        unary_exp.val = impl::unary_neg(arg1)
                    ]
                ;

            primary_exp
                =   constant[primary_exp.val = arg1]
                |   ch_p(T_LEFTPAREN) 
                    >> const_exp[primary_exp.val = arg1]
                    >> ch_p(T_RIGHTPAREN)
                ;

            constant
                =   ch_p(T_PP_NUMBER) 
                    [
                        constant.val = impl::as_intlit(arg1)
                    ]
                |   ch_p(T_INTLIT) 
                    [
                        constant.val = impl::as_intlit(arg1)
                    ]
                |   ch_p(T_CHARLIT) 
                    [
                        constant.val = impl::as_chlit(arg1)
                    ]
                ;
              
            //  here follows the same grammar, but without any embedded 
            //  calculations
            const_exp_nocalc
                =   logical_or_exp_nocalc
                    >> !(   ch_p(T_QUESTION_MARK)
                            >>  const_exp_nocalc
                            >>  ch_p(T_COLON)
                            >>  const_exp_nocalc
                        )
                ;

            logical_or_exp_nocalc 
                =   logical_and_exp_nocalc
                    >> *(   pattern_p(T_OROR, MainTokenMask)
                            >>  logical_and_exp_nocalc
                        )
                ;

            logical_and_exp_nocalc
                =   inclusive_or_exp_nocalc
                    >> *(   pattern_p(T_ANDAND, MainTokenMask)
                            >>  inclusive_or_exp_nocalc
                        )
                ;

            inclusive_or_exp_nocalc
                =   exclusive_or_exp_nocalc
                    >> *(   pattern_p(T_OR, MainTokenMask)
                            >>  exclusive_or_exp_nocalc
                        )
                ;

            exclusive_or_exp_nocalc
                =   and_exp_nocalc
                    >> *(   pattern_p(T_XOR, MainTokenMask)
                            >>  and_exp_nocalc
                        )
                ;

            and_exp_nocalc
                =   cmp_equality_nocalc
                    >> *(   pattern_p(T_AND, MainTokenMask)
                            >>  cmp_equality_nocalc
                        )
                ;

            cmp_equality_nocalc
                =   cmp_relational_nocalc
                    >> *(   ch_p(T_EQUAL)
                            >>  cmp_relational_nocalc
                        |   pattern_p(T_NOTEQUAL, MainTokenMask)
                            >>  cmp_relational_nocalc
                        )
                ;

            cmp_relational_nocalc
                =   shift_exp_nocalc
                    >> *(   ch_p(T_LESSEQUAL)
                            >>  shift_exp_nocalc
                        |   ch_p(T_GREATEREQUAL)
                            >>  shift_exp_nocalc
                        |   ch_p(T_LESS)
                            >>  shift_exp_nocalc
                        |   ch_p(T_GREATER)
                            >>  shift_exp_nocalc
                        )
                ;

            shift_exp_nocalc
                =   add_exp_nocalc
                    >> *(   ch_p(T_SHIFTLEFT)
                            >>  add_exp_nocalc
                        |   ch_p(T_SHIFTRIGHT)
                            >>  add_exp_nocalc
                        )
                ;

            add_exp_nocalc
                =   multiply_exp_nocalc
                    >> *(   ch_p(T_PLUS)
                            >>  multiply_exp_nocalc
                        |   ch_p(T_MINUS)
                            >>  multiply_exp_nocalc
                        )
                ;

            multiply_exp_nocalc
                =   unary_exp_nocalc
                    >> *(   ch_p(T_STAR)
                            >>  unary_exp_nocalc
                        |   ch_p(T_DIVIDE)
                            >>  unary_exp_nocalc
                        |   ch_p(T_PERCENT)
                            >>  unary_exp_nocalc
                        )
                ;

            unary_exp_nocalc
                =   primary_exp_nocalc
                |   ch_p(T_PLUS) >> unary_exp_nocalc
                |   ch_p(T_MINUS) >> unary_exp_nocalc
                |   pattern_p(T_COMPL, MainTokenMask) >> unary_exp_nocalc
                |   pattern_p(T_NOT, MainTokenMask) >> unary_exp_nocalc
                ;

            primary_exp_nocalc
                =   constant_nocalc
                |   ch_p(T_LEFTPAREN) 
                    >> const_exp_nocalc
                    >> ch_p(T_RIGHTPAREN)
                ;

            constant_nocalc
                =   ch_p(T_PP_NUMBER) 
                |   ch_p(T_INTLIT) 
                |   ch_p(T_CHARLIT) 
                ;

            BOOST_SPIRIT_DEBUG_TRACE_RULE(pp_expression, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(const_exp, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(logical_or_exp, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(logical_and_exp, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(inclusive_or_exp, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(exclusive_or_exp, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(and_exp, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(cmp_equality, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(cmp_relational, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(shift_exp, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(add_exp, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(multiply_exp, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(unary_exp, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(primary_exp, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(constant, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(const_exp_subrule, TRACE_CPP_EXPR_GRAMMAR);

            BOOST_SPIRIT_DEBUG_TRACE_RULE(const_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(logical_or_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(logical_and_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(inclusive_or_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(exclusive_or_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(and_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(cmp_equality_nocalc, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(cmp_relational_nocalc, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(shift_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(add_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(multiply_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(unary_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(primary_exp_nocalc, TRACE_CPP_EXPR_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(constant_nocalc, TRACE_CPP_EXPR_GRAMMAR);
        }

    // start rule of this grammar
        simple_rule_t const& start() const
        { return pp_expression; }
    };
};

///////////////////////////////////////////////////////////////////////////////
#undef TRACE_CPP_EXPR_GRAMMAR

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

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

template <typename TokenT>
BOOST_WAVE_EXPRGRAMMAR_GEN_INLINE 
bool 
expression_grammar_gen<TokenT>::evaluate(
    typename token_sequence_type::const_iterator const &first, 
    typename token_sequence_type::const_iterator const &last, 
    typename token_type::position_type const &act_pos,
    bool if_block_status, value_error &status)
{
    using namespace boost::spirit::classic;
    using namespace boost::wave;
    using namespace boost::wave::grammars::closures;
    
    using boost::wave::util::impl::as_string;
    
    typedef typename token_sequence_type::const_iterator iterator_type;
    typedef typename token_sequence_type::value_type::string_type string_type;

    parse_info<iterator_type> hit(first);
    closure_value result;             // expression result
    
#if !defined(BOOST_NO_EXCEPTIONS)
    try 
#endif
    {
        expression_grammar g;             // expression grammar
        hit = parse (first, last, g[spirit_assign_actor(result)], 
                     ch_p(T_SPACE) | ch_p(T_CCOMMENT) | ch_p(T_CPPCOMMENT));

        if (!hit.hit) {
        // expression is illformed
            if (if_block_status) {
                string_type expression = as_string<string_type>(first, last);
                if (0 == expression.size()) 
                    expression = "<empty expression>";
                BOOST_WAVE_THROW(preprocess_exception, ill_formed_expression, 
                    expression.c_str(), act_pos);
                return false;
            }
            else {
            //  as the if_block_status is false no errors will be reported
                return false;
            }
        }
    }
#if !defined(BOOST_NO_EXCEPTIONS)
    catch (boost::wave::preprocess_exception const& e) {
    // expression is illformed
        if (if_block_status) {
            boost::throw_exception(e);
            return false;
        }
        else         {
        //  as the if_block_status is false no errors will be reported
            return false;
        }
    }
#endif

    if (!hit.full) {
    // The token list starts with a valid expression, but there remains 
    // something. If the remainder consists out of whitespace only, the 
    // expression is still valid.
    iterator_type next = hit.stop;

        while (next != last) {
            switch (static_cast<unsigned int>(token_id(*next))) {
            case T_SPACE:
            case T_SPACE2:
            case T_CCOMMENT:
                break;                      // ok continue

            case T_NEWLINE:
            case T_EOF:
            case T_CPPCOMMENT:              // contains newline
                return as_bool(result);     // expression is valid

            default:
            // expression is illformed
                if (if_block_status) {
                    string_type expression = as_string<string_type>(first, last);
                    if (0 == expression.size()) 
                        expression = "<empty expression>";
                    BOOST_WAVE_THROW(preprocess_exception, ill_formed_expression, 
                        expression.c_str(), act_pos);
                    return false;
                }
                else {
                //  as the if_block_status is false no errors will be reported
                    return false;
                }
            }
            ++next;
        }
    }

    if (error_noerror != result.is_valid()) // division or other error by zero occurred
        status = result.is_valid();
    
// token sequence is a valid expression
    return as_bool(result);
}

#undef BOOST_WAVE_EXPRGRAMMAR_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_EXPRESSION_GRAMMAR_HPP_099CD1A4_A6C0_44BE_8F24_0B00F5BE5674_INCLUDED)
