/*=============================================================================

    Boost.Wave: A Standard compliant C++ preprocessor library



    http://www.boost.org/



    Copyright (c) 2001-2008 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/core.hpp>

#include <boost/spirit/attribute/closure.hpp>

#include <boost/spirit/dynamic/if.hpp>

#if SPIRIT_VERSION >= 0x1700

#include <boost/spirit/actor/assign_actor.hpp>

#include <boost/spirit/actor/push_back_actor.hpp>

#endif // SPIRIT_VERSION >= 0x1700



#include <boost/spirit/phoenix/functions.hpp>

#include <boost/spirit/phoenix/operators.hpp>

#include <boost/spirit/phoenix/primitives.hpp>

#include <boost/spirit/phoenix/statements.hpp>

#include <boost/spirit/phoenix/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)

#if SPIRIT_VERSION >= 0x1700

#define spirit_append_actor(actor) boost::spirit::push_back_a(actor)

#define spirit_assign_actor(actor) boost::spirit::assign_a(actor)

#else

#define spirit_append_actor(actor) boost::spirit::append(actor)

#define spirit_assign_actor(actor) boost::spirit::assign(actor)

#endif // SPIRIT_VERSION >= 0x1700

#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::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::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::rule<ScannerT, closure_type::context_t> rule_t;

        typedef boost::spirit::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::subrule<0, closure_type::context_t> const_exp_subrule;



        definition(expression_grammar const &self)

        {

            using namespace boost::spirit;

            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;

    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

    

    try {

        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);

            }

            else {

            //  as the if_block_status is false no errors will be reported

                return false;

            }

        }

    }

    catch (boost::wave::preprocess_exception const& e) {

    // expression is illformed

        if (if_block_status) {

            boost::throw_exception(e);

        }

        else {

        //  as the if_block_status is false no errors will be reported

            return false;

        }

    }

        

    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);

                }

                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)

