/*=============================================================================
    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(BOOST_CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED)
#define BOOST_CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED

#include <limits>     // std::numeric_limits
#include <climits>    // CHAR_BIT

#include <boost/wave/wave_config.hpp>

#include <boost/static_assert.hpp>
#include <boost/cstdint.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_operators.hpp>
#include <boost/spirit/include/phoenix1_primitives.hpp>
#include <boost/spirit/include/phoenix1_statements.hpp>
#include <boost/spirit/include/phoenix1_functions.hpp>

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

///////////////////////////////////////////////////////////////////////////////
//
//  Reusable grammar to parse a C++ style character literal
//
///////////////////////////////////////////////////////////////////////////////
namespace boost {
namespace wave {
namespace grammars {

namespace closures {

    struct chlit_closure
    :   boost::spirit::classic::closure<chlit_closure, boost::uint32_t, bool>
    {
        member1 value;
        member2 long_lit;
    };
}

namespace impl {

///////////////////////////////////////////////////////////////////////////////
//
//  compose a multibyte character literal
//
///////////////////////////////////////////////////////////////////////////////
    struct compose_character_literal {

        template <typename A1, typename A2, typename A3, typename A4>
        struct result
        {
            typedef void type;
        };

        void
        operator()(boost::uint32_t& value, bool long_lit, bool& overflow,
            boost::uint32_t character) const
        {
            // The following assumes that wchar_t is max. 32 Bit
            BOOST_STATIC_ASSERT(sizeof(wchar_t) <= 4);

            static boost::uint32_t masks[] = {
                0x000000ff, 0x0000ffff, 0x00ffffff, 0xffffffff
            };
            static boost::uint32_t overflow_masks[] = {
                0xff000000, 0xffff0000, 0xffffff00, 0xffffffff
            };

            if (long_lit) {
            // make sure no overflow will occur below
                if ((value & overflow_masks[sizeof(wchar_t)-1]) != 0) {
                    overflow |= true;
                }
                else {
                // calculate the new value (avoiding a warning regarding
                // shifting count >= size of the type)
                    value <<= CHAR_BIT * (sizeof(wchar_t)-1);
                    value <<= CHAR_BIT;
                    value |= character & masks[sizeof(wchar_t)-1];
                }
            }
            else {
            // make sure no overflow will occur below
                if ((value & overflow_masks[sizeof(char)-1]) != 0) {
                    overflow |= true;
                }
                else {
                // calculate the new value
                    value <<= CHAR_BIT * sizeof(char);
                    value |= character & masks[sizeof(char)-1];
                }
            }
        }
    };
    phoenix::function<compose_character_literal> const compose;

}   // namespace impl

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

struct chlit_grammar :
    public boost::spirit::classic::grammar<chlit_grammar,
        closures::chlit_closure::context_t>
{
    chlit_grammar()
    :   overflow(false)
    {
        BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "chlit_grammar",
            TRACE_CHLIT_GRAMMAR);
    }

    // no need for copy constructor/assignment operator
    chlit_grammar(chlit_grammar const&);
    chlit_grammar& operator=(chlit_grammar const&);

    template <typename ScannerT>
    struct definition
    {
        typedef boost::spirit::classic::rule<
                ScannerT, closures::chlit_closure::context_t>
            rule_t;

        rule_t ch_lit;

        definition(chlit_grammar const &self)
        {
            using namespace boost::spirit::classic;
            namespace phx = phoenix;

            // special parsers for '\x..' and L'\x....'
            typedef uint_parser<
                        unsigned int, 16, 1, 2 * sizeof(char)
                    > hex_char_parser_type;
            typedef uint_parser<
                        unsigned int, 16, 1, 2 * sizeof(wchar_t)
                    > hex_wchar_parser_type;

            // the rule for a character literal
            ch_lit
                =   eps_p[(self.value = phx::val(0), self.long_lit = phx::val(false))]
                    >> !ch_p('L')[self.long_lit = phx::val(true)]
                    >>  ch_p('\'')
                    >> +(   (
                            ch_p('\\')
                            >>  (   ch_p('a')    // BEL
                                    [
                                        impl::compose(self.value, self.long_lit,
                                            phx::var(self.overflow), phx::val(0x07))
                                    ]
                                |   ch_p('b')    // BS
                                    [
                                        impl::compose(self.value, self.long_lit,
                                            phx::var(self.overflow), phx::val(0x08))
                                    ]
                                |   ch_p('t')    // HT
                                    [
                                        impl::compose(self.value, self.long_lit,
                                            phx::var(self.overflow), phx::val(0x09))
                                    ]
                                |   ch_p('n')    // NL
                                    [
                                        impl::compose(self.value, self.long_lit,
                                            phx::var(self.overflow), phx::val(0x0a))
                                    ]
                                |   ch_p('v')    // VT
                                    [
                                        impl::compose(self.value, self.long_lit,
                                            phx::var(self.overflow), phx::val(0x0b))
                                    ]
                                |   (ch_p('e') | ch_p('E'))   // ESC
                                    [
                                        impl::compose(self.value, self.long_lit,
                                            phx::var(self.overflow), phx::val(0x1b))
                                    ]
                                |   ch_p('f')    // FF
                                    [
                                        impl::compose(self.value, self.long_lit,
                                            phx::var(self.overflow), phx::val(0x0c))
                                    ]
                                |   ch_p('r')    // CR
                                    [
                                        impl::compose(self.value, self.long_lit,
                                            phx::var(self.overflow), phx::val(0x0d))
                                    ]
                                |   ch_p('?')
                                    [
                                        impl::compose(self.value, self.long_lit,
                                            phx::var(self.overflow), phx::val('?'))
                                    ]
                                |   ch_p('\'')
                                    [
                                        impl::compose(self.value, self.long_lit,
                                            phx::var(self.overflow), phx::val('\''))
                                    ]
                                |   ch_p('\"')
                                    [
                                        impl::compose(self.value, self.long_lit,
                                            phx::var(self.overflow), phx::val('\"'))
                                    ]
                                |   ch_p('\\')
                                    [
                                        impl::compose(self.value, self.long_lit,
                                            phx::var(self.overflow), phx::val('\\'))
                                    ]
                                |   ch_p('x')
                                    >>  if_p(self.long_lit)
                                        [
                                            hex_wchar_parser_type()
                                            [
                                                impl::compose(self.value, self.long_lit,
                                                    phx::var(self.overflow), phx::arg1)
                                            ]
                                        ]
                                        .else_p
                                        [
                                            hex_char_parser_type()
                                            [
                                                impl::compose(self.value, self.long_lit,
                                                    phx::var(self.overflow), phx::arg1)
                                            ]
                                        ]
                                |   ch_p('u')
                                    >>  uint_parser<unsigned int, 16, 4, 4>()
                                        [
                                            impl::compose(self.value, self.long_lit,
                                                phx::var(self.overflow), phx::arg1)
                                        ]
                                |   ch_p('U')
                                    >>  uint_parser<unsigned int, 16, 8, 8>()
                                        [
                                            impl::compose(self.value, self.long_lit,
                                                phx::var(self.overflow), phx::arg1)
                                        ]
                                |   uint_parser<unsigned int, 8, 1, 3>()
                                    [
                                        impl::compose(self.value, self.long_lit,
                                            phx::var(self.overflow), phx::arg1)
                                    ]
                                )
                            )
                        |   ~eps_p(ch_p('\'')) >> anychar_p
                            [
                                impl::compose(self.value, self.long_lit,
                                    phx::var(self.overflow), phx::arg1)
                            ]
                        )
                    >>  ch_p('\'')
                ;

            BOOST_SPIRIT_DEBUG_TRACE_RULE(ch_lit, TRACE_CHLIT_GRAMMAR);
        }

        // start rule of this grammar
        rule_t const& start() const
        { return ch_lit; }
    };

    // flag signaling integer overflow during value composition
    mutable bool overflow;
};

#undef TRACE_CHLIT_GRAMMAR

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

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

template <typename IntegralResult, typename TokenT>
BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE
IntegralResult
chlit_grammar_gen<IntegralResult, TokenT>::evaluate(TokenT const &token, value_error &status)
{
    using namespace boost::spirit::classic;

chlit_grammar g;
IntegralResult 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_character_literal,
            token_val.c_str(), token.get_position());
    }
    else {
        // range check
        if ('L' == token_val[0]) {
            // recognized wide character
            if (g.overflow ||
                result > (IntegralResult)(std::numeric_limits<wchar_t>::max)())
            {
                // out of range
                status = error_character_overflow;
            }
        }
        else {
            // recognized narrow ('normal') character
            if (g.overflow ||
                result > (IntegralResult)(std::numeric_limits<unsigned char>::max)())
            {
                // out of range
                status = error_character_overflow;
            }
        }
    }
    return result;
}

#undef BOOST_WAVE_CHLITGRAMMAR_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(BOOST_CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED)