blob: 4da81c93ef229b27a1dc240a6c0c57db7e885b8d [file] [log] [blame]
/*=============================================================================
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