/*============================================================================= | |
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 | |
#include <boost/spirit/home/classic/core/parser.hpp> | |
#include <boost/spirit/home/classic/core/primitives/numerics.hpp> | |
#include <boost/spirit/home/classic/core/composite/difference.hpp> | |
#include <boost/spirit/home/classic/core/composite/sequence.hpp> | |
/////////////////////////////////////////////////////////////////////////////// | |
namespace boost { namespace spirit { | |
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// 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 <unsigned long Flags, typename CharT> | |
struct escape_char_action_parse { | |
template <typename ParserT, typename ScannerT> | |
static typename parser_result<ParserT, ScannerT>::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<ParserT, ScannerT>::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<char_t>::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<char_t>::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 <typename CharT> | |
struct escape_char_parse { | |
template <typename ScannerT, typename ParserT> | |
static typename parser_result<ParserT, ScannerT>::type | |
parse(ScannerT const &scan, ParserT const &/*p*/) | |
{ | |
typedef | |
uint_parser<CharT, 8, 1, | |
std::numeric_limits<CharT>::digits / 3 + 1 | |
> | |
oct_parser_t; | |
typedef | |
uint_parser<CharT, 16, 1, | |
std::numeric_limits<CharT>::digits / 4 + 1 | |
> | |
hex_parser_t; | |
typedef alternative<difference<anychar_parser, chlit<CharT> >, | |
sequence<chlit<CharT>, alternative<alternative<oct_parser_t, | |
sequence<inhibit_case<chlit<CharT> >, hex_parser_t > >, | |
difference<difference<anychar_parser, | |
inhibit_case<chlit<CharT> > >, oct_parser_t > > > > | |
parser_t; | |
static parser_t p = | |
( (anychar_p - chlit<CharT>(CharT('\\'))) | |
| (chlit<CharT>(CharT('\\')) >> | |
( oct_parser_t() | |
| as_lower_d[chlit<CharT>(CharT('x'))] >> hex_parser_t() | |
| (anychar_p - as_lower_d[chlit<CharT>(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 | |
/////////////////////////////////////////////////////////////////////////////// | |
BOOST_SPIRIT_CLASSIC_NAMESPACE_END | |
}} // namespace boost::spirit | |
#endif | |