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 |
|
---|