/*============================================================================= Copyright (c) 2001-2003 Daniel Nuffer Copyright (c) 2002-2003 Hartmut Kaiser http://spirit.sourceforge.net/ Use, modification and distribution is subject to 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) =============================================================================*/ #ifndef BOOST_SPIRIT_ESCAPE_CHAR_IPP #define BOOST_SPIRIT_ESCAPE_CHAR_IPP /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace spirit { /////////////////////////////////////////////////////////////////////////////// // // escape_char_parser class // /////////////////////////////////////////////////////////////////////////////// const unsigned long c_escapes = 1; const unsigned long lex_escapes = c_escapes << 1; ////////////////////////////////// namespace impl { ////////////////////////////////// #if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310)) #pragma warning(push) #pragma warning(disable:4127) #endif template struct escape_char_action_parse { template static typename parser_result::type parse(ScannerT const& scan, ParserT const &p) { // Actually decode the escape char. typedef CharT char_t; typedef typename ScannerT::iterator_t iterator_t; typedef typename parser_result::type result_t; if (scan.first != scan.last) { iterator_t save = scan.first; if (result_t hit = p.subject().parse(scan)) { char_t unescaped; scan.first = save; if (*scan.first == '\\') { ++scan.first; switch (*scan.first) { case 'b': unescaped = '\b'; ++scan.first; break; case 't': unescaped = '\t'; ++scan.first; break; case 'n': unescaped = '\n'; ++scan.first; break; case 'f': unescaped = '\f'; ++scan.first; break; case 'r': unescaped = '\r'; ++scan.first; break; case '"': unescaped = '"'; ++scan.first; break; case '\'': unescaped = '\''; ++scan.first; break; case '\\': unescaped = '\\'; ++scan.first; break; case 'x': case 'X': { char_t hex = 0; char_t const lim = (std::numeric_limits::max)() >> 4; ++scan.first; while (scan.first != scan.last) { char_t c = *scan.first; if (hex > lim && impl::isxdigit_(c)) { // overflow detected scan.first = save; return scan.no_match(); } if (impl::isdigit_(c)) { hex <<= 4; hex |= c - '0'; ++scan.first; } else if (impl::isxdigit_(c)) { hex <<= 4; c = impl::toupper_(c); hex |= c - 'A' + 0xA; ++scan.first; } else { break; // reached the end of the number } } unescaped = hex; } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { char_t oct = 0; char_t const lim = (std::numeric_limits::max)() >> 3; while (scan.first != scan.last) { char_t c = *scan.first; if (oct > lim && (c >= '0' && c <= '7')) { // overflow detected scan.first = save; return scan.no_match(); } if (c >= '0' && c <= '7') { oct <<= 3; oct |= c - '0'; ++scan.first; } else { break; // reached end of digits } } unescaped = oct; } break; default: if (Flags & c_escapes) { // illegal C escape sequence scan.first = save; return scan.no_match(); } else { unescaped = *scan.first; ++scan.first; } break; } } else { unescaped = *scan.first; ++scan.first; } scan.do_action(p.predicate(), unescaped, save, scan.first); return hit; } } return scan.no_match(); // overflow detected } }; #if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310)) #pragma warning(pop) #endif ////////////////////////////////// template struct escape_char_parse { template static typename parser_result::type parse(ScannerT const &scan, ParserT const &/*p*/) { typedef uint_parser::digits / 3 + 1 > oct_parser_t; typedef uint_parser::digits / 4 + 1 > hex_parser_t; typedef alternative >, sequence, alternative >, hex_parser_t > >, difference > >, oct_parser_t > > > > parser_t; static parser_t p = ( (anychar_p - chlit(CharT('\\'))) | (chlit(CharT('\\')) >> ( oct_parser_t() | as_lower_d[chlit(CharT('x'))] >> hex_parser_t() | (anychar_p - as_lower_d[chlit(CharT('x'))] - oct_parser_t()) ) )); BOOST_SPIRIT_DEBUG_TRACE_NODE(p, (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_ESCAPE_CHAR) != 0); return p.parse(scan); } }; /////////////////////////////////////////////////////////////////////////////// } // namespace impl /////////////////////////////////////////////////////////////////////////////// }} // namespace boost::spirit #endif