Chris@16: /*============================================================================= Chris@16: Boost.Wave: A Standard compliant C++ preprocessor library Chris@16: Chris@16: http://www.boost.org/ Chris@16: Chris@16: Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost Chris@16: Software License, Version 1.0. (See accompanying file Chris@16: LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: =============================================================================*/ Chris@16: Chris@16: #if !defined(CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED) Chris@16: #define CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED Chris@16: Chris@16: #include // std::numeric_limits Chris@16: #include // CHAR_BIT Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: Chris@16: #if !defined(spirit_append_actor) Chris@16: #define spirit_append_actor(actor) boost::spirit::classic::push_back_a(actor) Chris@16: #define spirit_assign_actor(actor) boost::spirit::classic::assign_a(actor) Chris@16: #endif // !defined(spirit_append_actor) Chris@16: Chris@16: // this must occur after all of the includes and before any code appears Chris@16: #ifdef BOOST_HAS_ABI_HEADERS Chris@16: #include BOOST_ABI_PREFIX Chris@16: #endif Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // Reusable grammar to parse a C++ style character literal Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: namespace boost { Chris@16: namespace wave { Chris@16: namespace grammars { Chris@16: Chris@16: namespace closures { Chris@16: Chris@16: struct chlit_closure Chris@16: : boost::spirit::classic::closure Chris@16: { Chris@16: member1 value; Chris@16: member2 long_lit; Chris@16: }; Chris@16: } Chris@16: Chris@16: namespace impl { Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // compose a multibyte character literal Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: struct compose_character_literal { Chris@16: Chris@16: template Chris@16: struct result Chris@16: { Chris@16: typedef void type; Chris@16: }; Chris@16: Chris@16: void Chris@16: operator()(boost::uint32_t& value, bool long_lit, bool& overflow, Chris@16: boost::uint32_t character) const Chris@16: { Chris@16: // The following assumes that wchar_t is max. 32 Bit Chris@16: BOOST_STATIC_ASSERT(sizeof(wchar_t) <= 4); Chris@16: Chris@16: static boost::uint32_t masks[] = { Chris@16: 0x000000ff, 0x0000ffff, 0x00ffffff, 0xffffffff Chris@16: }; Chris@16: static boost::uint32_t overflow_masks[] = { Chris@16: 0xff000000, 0xffff0000, 0xffffff00, 0xffffffff Chris@16: }; Chris@16: Chris@16: if (long_lit) { Chris@16: // make sure no overflow will occur below Chris@16: if ((value & overflow_masks[sizeof(wchar_t)-1]) != 0) { Chris@16: overflow |= true; Chris@16: } Chris@16: else { Chris@16: // calculate the new value (avoiding a warning regarding Chris@16: // shifting count >= size of the type) Chris@16: value <<= CHAR_BIT * (sizeof(wchar_t)-1); Chris@16: value <<= CHAR_BIT; Chris@16: value |= character & masks[sizeof(wchar_t)-1]; Chris@16: } Chris@16: } Chris@16: else { Chris@16: // make sure no overflow will occur below Chris@16: if ((value & overflow_masks[sizeof(char)-1]) != 0) { Chris@16: overflow |= true; Chris@16: } Chris@16: else { Chris@16: // calculate the new value Chris@16: value <<= CHAR_BIT * sizeof(char); Chris@16: value |= character & masks[sizeof(char)-1]; Chris@16: } Chris@16: } Chris@16: } Chris@16: }; Chris@16: phoenix::function const compose; Chris@16: Chris@16: } // namespace impl Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // define, whether the rule's should generate some debug output Chris@16: #define TRACE_CHLIT_GRAMMAR \ Chris@16: bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CHLIT_GRAMMAR) \ Chris@16: /**/ Chris@16: Chris@16: struct chlit_grammar : Chris@16: public boost::spirit::classic::grammar Chris@16: { Chris@16: chlit_grammar() Chris@16: : overflow(false) Chris@16: { Chris@16: BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "chlit_grammar", Chris@16: TRACE_CHLIT_GRAMMAR); Chris@16: } Chris@16: Chris@16: // no need for copy constructor/assignment operator Chris@16: chlit_grammar(chlit_grammar const&); Chris@16: chlit_grammar& operator=(chlit_grammar const&); Chris@16: Chris@16: template Chris@16: struct definition Chris@16: { Chris@16: typedef boost::spirit::classic::rule< Chris@16: ScannerT, closures::chlit_closure::context_t> Chris@16: rule_t; Chris@16: Chris@16: rule_t ch_lit; Chris@16: Chris@16: definition(chlit_grammar const &self) Chris@16: { Chris@16: using namespace boost::spirit::classic; Chris@16: namespace phx = phoenix; Chris@16: Chris@16: // special parsers for '\x..' and L'\x....' Chris@16: typedef uint_parser< Chris@16: unsigned int, 16, 1, 2 * sizeof(char) Chris@16: > hex_char_parser_type; Chris@16: typedef uint_parser< Chris@16: unsigned int, 16, 1, 2 * sizeof(wchar_t) Chris@16: > hex_wchar_parser_type; Chris@16: Chris@16: // the rule for a character literal Chris@16: ch_lit Chris@16: = eps_p[self.value = phx::val(0), self.long_lit = phx::val(false)] Chris@16: >> !ch_p('L')[self.long_lit = phx::val(true)] Chris@16: >> ch_p('\'') Chris@16: >> +( ( Chris@16: ch_p('\\') Chris@16: >> ( ch_p('a') // BEL Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::val(0x07)) Chris@16: ] Chris@16: | ch_p('b') // BS Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::val(0x08)) Chris@16: ] Chris@16: | ch_p('t') // HT Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::val(0x09)) Chris@16: ] Chris@16: | ch_p('n') // NL Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::val(0x0a)) Chris@16: ] Chris@16: | ch_p('v') // VT Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::val(0x0b)) Chris@16: ] Chris@16: | ch_p('f') // FF Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::val(0x0c)) Chris@16: ] Chris@16: | ch_p('r') // CR Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::val(0x0d)) Chris@16: ] Chris@16: | ch_p('?') Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::val('?')) Chris@16: ] Chris@16: | ch_p('\'') Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::val('\'')) Chris@16: ] Chris@16: | ch_p('\"') Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::val('\"')) Chris@16: ] Chris@16: | ch_p('\\') Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::val('\\')) Chris@16: ] Chris@16: | ch_p('x') Chris@16: >> if_p(self.long_lit) Chris@16: [ Chris@16: hex_wchar_parser_type() Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::arg1) Chris@16: ] Chris@16: ] Chris@16: .else_p Chris@16: [ Chris@16: hex_char_parser_type() Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::arg1) Chris@16: ] Chris@16: ] Chris@16: | ch_p('u') Chris@16: >> uint_parser() Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::arg1) Chris@16: ] Chris@16: | ch_p('U') Chris@16: >> uint_parser() Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::arg1) Chris@16: ] Chris@16: | uint_parser() Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::arg1) Chris@16: ] Chris@16: ) Chris@16: ) Chris@16: | ~eps_p(ch_p('\'')) >> anychar_p Chris@16: [ Chris@16: impl::compose(self.value, self.long_lit, Chris@16: phx::var(self.overflow), phx::arg1) Chris@16: ] Chris@16: ) Chris@16: >> ch_p('\'') Chris@16: ; Chris@16: Chris@16: BOOST_SPIRIT_DEBUG_TRACE_RULE(ch_lit, TRACE_CHLIT_GRAMMAR); Chris@16: } Chris@16: Chris@16: // start rule of this grammar Chris@16: rule_t const& start() const Chris@16: { return ch_lit; } Chris@16: }; Chris@16: Chris@16: // flag signaling integer overflow during value composition Chris@16: mutable bool overflow; Chris@16: }; Chris@16: Chris@16: #undef TRACE_CHLIT_GRAMMAR Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // The following function is defined here, to allow the separation of Chris@16: // the compilation of the intlit_grammap from the function using it. Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 Chris@16: #define BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE Chris@16: #else Chris@16: #define BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE inline Chris@16: #endif Chris@16: Chris@16: template Chris@16: BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE Chris@16: IntegralResult Chris@16: chlit_grammar_gen::evaluate(TokenT const &token, value_error &status) Chris@16: { Chris@16: using namespace boost::spirit::classic; Chris@16: Chris@16: chlit_grammar g; Chris@16: IntegralResult result = 0; Chris@16: typename TokenT::string_type const &token_val = token.get_value(); Chris@16: parse_info hit = Chris@16: parse(token_val.begin(), token_val.end(), g[spirit_assign_actor(result)]); Chris@16: Chris@16: if (!hit.hit) { Chris@16: BOOST_WAVE_THROW(preprocess_exception, ill_formed_character_literal, Chris@16: token_val.c_str(), token.get_position()); Chris@16: } Chris@16: else { Chris@16: // range check Chris@16: if ('L' == token_val[0]) { Chris@16: // recognized wide character Chris@16: if (g.overflow || Chris@16: result > (IntegralResult)(std::numeric_limits::max)()) Chris@16: { Chris@16: // out of range Chris@16: status = error_character_overflow; Chris@16: } Chris@16: } Chris@16: else { Chris@16: // recognized narrow ('normal') character Chris@16: if (g.overflow || Chris@16: result > (IntegralResult)(std::numeric_limits::max)()) Chris@16: { Chris@16: // out of range Chris@16: status = error_character_overflow; Chris@16: } Chris@16: } Chris@16: } Chris@16: return result; Chris@16: } Chris@16: Chris@16: #undef BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: } // namespace grammars Chris@16: } // namespace wave Chris@16: } // namespace boost Chris@16: Chris@16: // the suffix header occurs after all of the code Chris@16: #ifdef BOOST_HAS_ABI_HEADERS Chris@16: #include BOOST_ABI_SUFFIX Chris@16: #endif Chris@16: Chris@16: #endif // !defined(CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED)