]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | /////////////////////////////////////////////////////////////////////////////// | |
19 | namespace boost { namespace spirit { | |
20 | ||
21 | BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN | |
22 | ||
23 | /////////////////////////////////////////////////////////////////////////////// | |
24 | // | |
25 | // escape_char_parser class | |
26 | // | |
27 | /////////////////////////////////////////////////////////////////////////////// | |
28 | ||
29 | const unsigned long c_escapes = 1; | |
30 | const unsigned long lex_escapes = c_escapes << 1; | |
31 | ||
32 | ////////////////////////////////// | |
33 | namespace impl { | |
34 | ||
35 | ////////////////////////////////// | |
36 | #if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310)) | |
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) && (BOOST_MSVC <= 1310)) | |
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 | /////////////////////////////////////////////////////////////////////////////// | |
219 | BOOST_SPIRIT_CLASSIC_NAMESPACE_END | |
220 | ||
221 | }} // namespace boost::spirit | |
222 | ||
223 | #endif | |
224 |