1/*============================================================================= 2 Copyright (c) 2001-2003 Daniel Nuffer 3 Copyright (c) 2002-2003 Hartmut Kaiser 4 http://spirit.sourceforge.net/ 5 6 Use, modification and distribution is subject to the Boost Software 7 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 8 http://www.boost.org/LICENSE_1_0.txt) 9=============================================================================*/ 10#ifndef BOOST_SPIRIT_ESCAPE_CHAR_IPP 11#define BOOST_SPIRIT_ESCAPE_CHAR_IPP 12 13#include <boost/spirit/home/classic/core/parser.hpp> 14#include <boost/spirit/home/classic/core/primitives/numerics.hpp> 15#include <boost/spirit/home/classic/core/composite/difference.hpp> 16#include <boost/spirit/home/classic/core/composite/sequence.hpp> 17 18/////////////////////////////////////////////////////////////////////////////// 19namespace boost { namespace spirit { 20 21BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN 22 23/////////////////////////////////////////////////////////////////////////////// 24// 25// escape_char_parser class 26// 27/////////////////////////////////////////////////////////////////////////////// 28 29const unsigned long c_escapes = 1; 30const unsigned long lex_escapes = c_escapes << 1; 31 32////////////////////////////////// 33namespace impl { 34 35 ////////////////////////////////// 36#if defined(BOOST_MSVC) 37#pragma warning(push) 38#pragma warning(disable:4127) 39#endif 40 template <unsigned long Flags, typename CharT> 41 struct escape_char_action_parse { 42 43 template <typename ParserT, typename ScannerT> 44 static typename parser_result<ParserT, ScannerT>::type 45 parse(ScannerT const& scan, ParserT const &p) 46 { 47 // Actually decode the escape char. 48 typedef CharT char_t; 49 typedef typename ScannerT::iterator_t iterator_t; 50 typedef typename parser_result<ParserT, ScannerT>::type result_t; 51 52 if (scan.first != scan.last) { 53 54 iterator_t save = scan.first; 55 if (result_t hit = p.subject().parse(scan)) { 56 57 char_t unescaped; 58 59 scan.first = save; 60 if (*scan.first == '\\') { 61 62 ++scan.first; 63 switch (*scan.first) { 64 case 'b': unescaped = '\b'; ++scan.first; break; 65 case 't': unescaped = '\t'; ++scan.first; break; 66 case 'n': unescaped = '\n'; ++scan.first; break; 67 case 'f': unescaped = '\f'; ++scan.first; break; 68 case 'r': unescaped = '\r'; ++scan.first; break; 69 case '"': unescaped = '"'; ++scan.first; break; 70 case '\'': unescaped = '\''; ++scan.first; break; 71 case '\\': unescaped = '\\'; ++scan.first; break; 72 73 case 'x': case 'X': 74 { 75 char_t hex = 0; 76 char_t const lim = 77 (std::numeric_limits<char_t>::max)() >> 4; 78 79 ++scan.first; 80 while (scan.first != scan.last) 81 { 82 char_t c = *scan.first; 83 if (hex > lim && impl::isxdigit_(c)) 84 { 85 // overflow detected 86 scan.first = save; 87 return scan.no_match(); 88 } 89 if (impl::isdigit_(c)) 90 { 91 hex <<= 4; 92 hex |= c - '0'; 93 ++scan.first; 94 } 95 else if (impl::isxdigit_(c)) 96 { 97 hex <<= 4; 98 c = impl::toupper_(c); 99 hex |= c - 'A' + 0xA; 100 ++scan.first; 101 } 102 else 103 { 104 break; // reached the end of the number 105 } 106 } 107 unescaped = hex; 108 } 109 break; 110 111 case '0': case '1': case '2': case '3': 112 case '4': case '5': case '6': case '7': 113 { 114 char_t oct = 0; 115 char_t const lim = 116 (std::numeric_limits<char_t>::max)() >> 3; 117 while (scan.first != scan.last) 118 { 119 char_t c = *scan.first; 120 if (oct > lim && (c >= '0' && c <= '7')) 121 { 122 // overflow detected 123 scan.first = save; 124 return scan.no_match(); 125 } 126 127 if (c >= '0' && c <= '7') 128 { 129 oct <<= 3; 130 oct |= c - '0'; 131 ++scan.first; 132 } 133 else 134 { 135 break; // reached end of digits 136 } 137 } 138 unescaped = oct; 139 } 140 break; 141 142 default: 143 if (Flags & c_escapes) 144 { 145 // illegal C escape sequence 146 scan.first = save; 147 return scan.no_match(); 148 } 149 else 150 { 151 unescaped = *scan.first; 152 ++scan.first; 153 } 154 break; 155 } 156 } 157 else { 158 unescaped = *scan.first; 159 ++scan.first; 160 } 161 162 scan.do_action(p.predicate(), unescaped, save, scan.first); 163 return hit; 164 } 165 } 166 return scan.no_match(); // overflow detected 167 } 168 }; 169#if defined(BOOST_MSVC) 170#pragma warning(pop) 171#endif 172 173 ////////////////////////////////// 174 template <typename CharT> 175 struct escape_char_parse { 176 177 template <typename ScannerT, typename ParserT> 178 static typename parser_result<ParserT, ScannerT>::type 179 parse(ScannerT const &scan, ParserT const &/*p*/) 180 { 181 typedef 182 uint_parser<CharT, 8, 1, 183 std::numeric_limits<CharT>::digits / 3 + 1 184 > 185 oct_parser_t; 186 typedef 187 uint_parser<CharT, 16, 1, 188 std::numeric_limits<CharT>::digits / 4 + 1 189 > 190 hex_parser_t; 191 192 typedef alternative<difference<anychar_parser, chlit<CharT> >, 193 sequence<chlit<CharT>, alternative<alternative<oct_parser_t, 194 sequence<inhibit_case<chlit<CharT> >, hex_parser_t > >, 195 difference<difference<anychar_parser, 196 inhibit_case<chlit<CharT> > >, oct_parser_t > > > > 197 parser_t; 198 199 static parser_t p = 200 ( (anychar_p - chlit<CharT>(CharT('\\'))) 201 | (chlit<CharT>(CharT('\\')) >> 202 ( oct_parser_t() 203 | as_lower_d[chlit<CharT>(CharT('x'))] >> hex_parser_t() 204 | (anychar_p - as_lower_d[chlit<CharT>(CharT('x'))] - oct_parser_t()) 205 ) 206 )); 207 208 BOOST_SPIRIT_DEBUG_TRACE_NODE(p, 209 (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_ESCAPE_CHAR) != 0); 210 211 return p.parse(scan); 212 } 213 }; 214 215/////////////////////////////////////////////////////////////////////////////// 216} // namespace impl 217 218/////////////////////////////////////////////////////////////////////////////// 219BOOST_SPIRIT_CLASSIC_NAMESPACE_END 220 221}} // namespace boost::spirit 222 223#endif 224 225