/*=============================================================================
    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_INTLIT_GRAMMAR_HPP_2E1E70B1_F15C_4132_8554_10A231B0D91C_INCLUDED)
#define CPP_INTLIT_GRAMMAR_HPP_2E1E70B1_F15C_4132_8554_10A231B0D91C_INCLUDED

#include <boost/wave/wave_config.hpp>

#include <boost/spirit/core.hpp>
#include <boost/spirit/attribute/closure.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/operators.hpp>
#include <boost/spirit/phoenix/primitives.hpp>
#include <boost/spirit/phoenix/statements.hpp>

#include <boost/wave/cpp_exceptions.hpp>
#include <boost/wave/grammars/cpp_literal_grammar_gen.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

///////////////////////////////////////////////////////////////////////////////
//
//  Reusable grammar for parsing of C++ style integer literals
//
///////////////////////////////////////////////////////////////////////////////
namespace boost {
namespace wave { 
namespace grammars {

///////////////////////////////////////////////////////////////////////////////
namespace closures {

    struct intlit_closure 
    :   boost::spirit::closure<intlit_closure, uint_literal_type> 
    {
        member1 val;
    };
}

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

struct intlit_grammar :
    boost::spirit::grammar<intlit_grammar, closures::intlit_closure::context_t>
{
    intlit_grammar(bool &is_unsigned_) : is_unsigned(is_unsigned_)
    {
        BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "intlit_grammar", 
            TRACE_INTLIT_GRAMMAR);
    }
    
    template <typename ScannerT>
    struct definition
    {
        typedef boost::spirit::rule<ScannerT> rule_t;

        rule_t int_lit;
        boost::spirit::subrule<0> sub_int_lit;
        boost::spirit::subrule<1> oct_lit;
        boost::spirit::subrule<2> hex_lit;
        boost::spirit::subrule<3> dec_lit;

        definition(intlit_grammar const &self)
        {
            using namespace boost::spirit;
            using namespace phoenix;
            
            int_lit = (
                    sub_int_lit = 
                        (    ch_p('0')[self.val = 0] >> (hex_lit | oct_lit)
                        |   dec_lit
                        )
                        >> !as_lower_d[
                                (ch_p('u')[var(self.is_unsigned) = true] || ch_p('l')) 
                            |   (ch_p('l') || ch_p('u')[var(self.is_unsigned) = true])
                            ]
                    ,

                    hex_lit =
                            (ch_p('X') | ch_p('x'))
                        >>  uint_parser<uint_literal_type, 16>()
                            [
                                self.val = arg1,
                                var(self.is_unsigned) = true
                            ]
                    ,
                        
                    oct_lit =
                       !uint_parser<uint_literal_type, 8>()
                        [
                            self.val = arg1,
                            var(self.is_unsigned) = true
                        ]
                    ,
                        
                    dec_lit =
                        uint_parser<uint_literal_type, 10>()
                        [
                            self.val = arg1
                        ]
                    )
                ;
                
            BOOST_SPIRIT_DEBUG_TRACE_RULE(int_lit, TRACE_INTLIT_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(sub_int_lit, TRACE_INTLIT_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(hex_lit, TRACE_INTLIT_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(oct_lit, TRACE_INTLIT_GRAMMAR);
            BOOST_SPIRIT_DEBUG_TRACE_RULE(dec_lit, TRACE_INTLIT_GRAMMAR);
        }

    // start rule of this grammar
        rule_t const& start() const
        { return int_lit; }
    };
    
    bool &is_unsigned;
};

#undef TRACE_INTLIT_GRAMMAR

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

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

template <typename TokenT>
BOOST_WAVE_INTLITGRAMMAR_GEN_INLINE 
uint_literal_type 
intlit_grammar_gen<TokenT>::evaluate(TokenT const &token, 
    bool &is_unsigned)
{
    using namespace boost::spirit;
    
intlit_grammar g(is_unsigned);
uint_literal_type result = 0;
typename TokenT::string_type const &token_val = token.get_value();
parse_info<typename TokenT::string_type::const_iterator> hit =
    parse(token_val.begin(), token_val.end(), g[spirit_assign_actor(result)]);

    if (!hit.hit) {
        BOOST_WAVE_THROW(preprocess_exception, ill_formed_integer_literal, 
            token_val.c_str(), token.get_position());
    }
    return result;
}

#undef BOOST_WAVE_INTLITGRAMMAR_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_INTLIT_GRAMMAR_HPP_2E1E70B1_F15C_4132_8554_10A231B0D91C_INCLUDED)
