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