Chris@16
|
1 /*=============================================================================
|
Chris@16
|
2 Boost.Wave: A Standard compliant C++ preprocessor library
|
Chris@16
|
3
|
Chris@16
|
4 http://www.boost.org/
|
Chris@16
|
5
|
Chris@16
|
6 Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
|
Chris@16
|
7 Software License, Version 1.0. (See accompanying file
|
Chris@16
|
8 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
9 =============================================================================*/
|
Chris@16
|
10
|
Chris@16
|
11 #if !defined(CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED)
|
Chris@16
|
12 #define CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED
|
Chris@16
|
13
|
Chris@16
|
14 #include <limits> // std::numeric_limits
|
Chris@16
|
15 #include <climits> // CHAR_BIT
|
Chris@16
|
16
|
Chris@16
|
17 #include <boost/wave/wave_config.hpp>
|
Chris@16
|
18
|
Chris@16
|
19 #include <boost/static_assert.hpp>
|
Chris@16
|
20 #include <boost/cstdint.hpp>
|
Chris@16
|
21
|
Chris@16
|
22 #include <boost/spirit/include/classic_core.hpp>
|
Chris@16
|
23 #include <boost/spirit/include/classic_closure.hpp>
|
Chris@16
|
24 #include <boost/spirit/include/classic_if.hpp>
|
Chris@16
|
25 #include <boost/spirit/include/classic_assign_actor.hpp>
|
Chris@16
|
26 #include <boost/spirit/include/classic_push_back_actor.hpp>
|
Chris@16
|
27
|
Chris@16
|
28 #include <boost/spirit/include/phoenix1_operators.hpp>
|
Chris@16
|
29 #include <boost/spirit/include/phoenix1_primitives.hpp>
|
Chris@16
|
30 #include <boost/spirit/include/phoenix1_statements.hpp>
|
Chris@16
|
31 #include <boost/spirit/include/phoenix1_functions.hpp>
|
Chris@16
|
32
|
Chris@16
|
33 #include <boost/wave/cpp_exceptions.hpp>
|
Chris@16
|
34 #include <boost/wave/grammars/cpp_literal_grammar_gen.hpp>
|
Chris@16
|
35
|
Chris@16
|
36 #if !defined(spirit_append_actor)
|
Chris@16
|
37 #define spirit_append_actor(actor) boost::spirit::classic::push_back_a(actor)
|
Chris@16
|
38 #define spirit_assign_actor(actor) boost::spirit::classic::assign_a(actor)
|
Chris@16
|
39 #endif // !defined(spirit_append_actor)
|
Chris@16
|
40
|
Chris@16
|
41 // this must occur after all of the includes and before any code appears
|
Chris@16
|
42 #ifdef BOOST_HAS_ABI_HEADERS
|
Chris@16
|
43 #include BOOST_ABI_PREFIX
|
Chris@16
|
44 #endif
|
Chris@16
|
45
|
Chris@16
|
46 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
47 //
|
Chris@16
|
48 // Reusable grammar to parse a C++ style character literal
|
Chris@16
|
49 //
|
Chris@16
|
50 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
51 namespace boost {
|
Chris@16
|
52 namespace wave {
|
Chris@16
|
53 namespace grammars {
|
Chris@16
|
54
|
Chris@16
|
55 namespace closures {
|
Chris@16
|
56
|
Chris@16
|
57 struct chlit_closure
|
Chris@16
|
58 : boost::spirit::classic::closure<chlit_closure, boost::uint32_t, bool>
|
Chris@16
|
59 {
|
Chris@16
|
60 member1 value;
|
Chris@16
|
61 member2 long_lit;
|
Chris@16
|
62 };
|
Chris@16
|
63 }
|
Chris@16
|
64
|
Chris@16
|
65 namespace impl {
|
Chris@16
|
66
|
Chris@16
|
67 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
68 //
|
Chris@16
|
69 // compose a multibyte character literal
|
Chris@16
|
70 //
|
Chris@16
|
71 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
72 struct compose_character_literal {
|
Chris@16
|
73
|
Chris@16
|
74 template <typename A1, typename A2, typename A3, typename A4>
|
Chris@16
|
75 struct result
|
Chris@16
|
76 {
|
Chris@16
|
77 typedef void type;
|
Chris@16
|
78 };
|
Chris@16
|
79
|
Chris@16
|
80 void
|
Chris@16
|
81 operator()(boost::uint32_t& value, bool long_lit, bool& overflow,
|
Chris@16
|
82 boost::uint32_t character) const
|
Chris@16
|
83 {
|
Chris@16
|
84 // The following assumes that wchar_t is max. 32 Bit
|
Chris@16
|
85 BOOST_STATIC_ASSERT(sizeof(wchar_t) <= 4);
|
Chris@16
|
86
|
Chris@16
|
87 static boost::uint32_t masks[] = {
|
Chris@16
|
88 0x000000ff, 0x0000ffff, 0x00ffffff, 0xffffffff
|
Chris@16
|
89 };
|
Chris@16
|
90 static boost::uint32_t overflow_masks[] = {
|
Chris@16
|
91 0xff000000, 0xffff0000, 0xffffff00, 0xffffffff
|
Chris@16
|
92 };
|
Chris@16
|
93
|
Chris@16
|
94 if (long_lit) {
|
Chris@16
|
95 // make sure no overflow will occur below
|
Chris@16
|
96 if ((value & overflow_masks[sizeof(wchar_t)-1]) != 0) {
|
Chris@16
|
97 overflow |= true;
|
Chris@16
|
98 }
|
Chris@16
|
99 else {
|
Chris@16
|
100 // calculate the new value (avoiding a warning regarding
|
Chris@16
|
101 // shifting count >= size of the type)
|
Chris@16
|
102 value <<= CHAR_BIT * (sizeof(wchar_t)-1);
|
Chris@16
|
103 value <<= CHAR_BIT;
|
Chris@16
|
104 value |= character & masks[sizeof(wchar_t)-1];
|
Chris@16
|
105 }
|
Chris@16
|
106 }
|
Chris@16
|
107 else {
|
Chris@16
|
108 // make sure no overflow will occur below
|
Chris@16
|
109 if ((value & overflow_masks[sizeof(char)-1]) != 0) {
|
Chris@16
|
110 overflow |= true;
|
Chris@16
|
111 }
|
Chris@16
|
112 else {
|
Chris@16
|
113 // calculate the new value
|
Chris@16
|
114 value <<= CHAR_BIT * sizeof(char);
|
Chris@16
|
115 value |= character & masks[sizeof(char)-1];
|
Chris@16
|
116 }
|
Chris@16
|
117 }
|
Chris@16
|
118 }
|
Chris@16
|
119 };
|
Chris@16
|
120 phoenix::function<compose_character_literal> const compose;
|
Chris@16
|
121
|
Chris@16
|
122 } // namespace impl
|
Chris@16
|
123
|
Chris@16
|
124 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
125 // define, whether the rule's should generate some debug output
|
Chris@16
|
126 #define TRACE_CHLIT_GRAMMAR \
|
Chris@16
|
127 bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CHLIT_GRAMMAR) \
|
Chris@16
|
128 /**/
|
Chris@16
|
129
|
Chris@16
|
130 struct chlit_grammar :
|
Chris@16
|
131 public boost::spirit::classic::grammar<chlit_grammar,
|
Chris@16
|
132 closures::chlit_closure::context_t>
|
Chris@16
|
133 {
|
Chris@16
|
134 chlit_grammar()
|
Chris@16
|
135 : overflow(false)
|
Chris@16
|
136 {
|
Chris@16
|
137 BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "chlit_grammar",
|
Chris@16
|
138 TRACE_CHLIT_GRAMMAR);
|
Chris@16
|
139 }
|
Chris@16
|
140
|
Chris@16
|
141 // no need for copy constructor/assignment operator
|
Chris@16
|
142 chlit_grammar(chlit_grammar const&);
|
Chris@16
|
143 chlit_grammar& operator=(chlit_grammar const&);
|
Chris@16
|
144
|
Chris@16
|
145 template <typename ScannerT>
|
Chris@16
|
146 struct definition
|
Chris@16
|
147 {
|
Chris@16
|
148 typedef boost::spirit::classic::rule<
|
Chris@16
|
149 ScannerT, closures::chlit_closure::context_t>
|
Chris@16
|
150 rule_t;
|
Chris@16
|
151
|
Chris@16
|
152 rule_t ch_lit;
|
Chris@16
|
153
|
Chris@16
|
154 definition(chlit_grammar const &self)
|
Chris@16
|
155 {
|
Chris@16
|
156 using namespace boost::spirit::classic;
|
Chris@16
|
157 namespace phx = phoenix;
|
Chris@16
|
158
|
Chris@16
|
159 // special parsers for '\x..' and L'\x....'
|
Chris@16
|
160 typedef uint_parser<
|
Chris@16
|
161 unsigned int, 16, 1, 2 * sizeof(char)
|
Chris@16
|
162 > hex_char_parser_type;
|
Chris@16
|
163 typedef uint_parser<
|
Chris@16
|
164 unsigned int, 16, 1, 2 * sizeof(wchar_t)
|
Chris@16
|
165 > hex_wchar_parser_type;
|
Chris@16
|
166
|
Chris@16
|
167 // the rule for a character literal
|
Chris@16
|
168 ch_lit
|
Chris@16
|
169 = eps_p[self.value = phx::val(0), self.long_lit = phx::val(false)]
|
Chris@16
|
170 >> !ch_p('L')[self.long_lit = phx::val(true)]
|
Chris@16
|
171 >> ch_p('\'')
|
Chris@16
|
172 >> +( (
|
Chris@16
|
173 ch_p('\\')
|
Chris@16
|
174 >> ( ch_p('a') // BEL
|
Chris@16
|
175 [
|
Chris@16
|
176 impl::compose(self.value, self.long_lit,
|
Chris@16
|
177 phx::var(self.overflow), phx::val(0x07))
|
Chris@16
|
178 ]
|
Chris@16
|
179 | ch_p('b') // BS
|
Chris@16
|
180 [
|
Chris@16
|
181 impl::compose(self.value, self.long_lit,
|
Chris@16
|
182 phx::var(self.overflow), phx::val(0x08))
|
Chris@16
|
183 ]
|
Chris@16
|
184 | ch_p('t') // HT
|
Chris@16
|
185 [
|
Chris@16
|
186 impl::compose(self.value, self.long_lit,
|
Chris@16
|
187 phx::var(self.overflow), phx::val(0x09))
|
Chris@16
|
188 ]
|
Chris@16
|
189 | ch_p('n') // NL
|
Chris@16
|
190 [
|
Chris@16
|
191 impl::compose(self.value, self.long_lit,
|
Chris@16
|
192 phx::var(self.overflow), phx::val(0x0a))
|
Chris@16
|
193 ]
|
Chris@16
|
194 | ch_p('v') // VT
|
Chris@16
|
195 [
|
Chris@16
|
196 impl::compose(self.value, self.long_lit,
|
Chris@16
|
197 phx::var(self.overflow), phx::val(0x0b))
|
Chris@16
|
198 ]
|
Chris@16
|
199 | ch_p('f') // FF
|
Chris@16
|
200 [
|
Chris@16
|
201 impl::compose(self.value, self.long_lit,
|
Chris@16
|
202 phx::var(self.overflow), phx::val(0x0c))
|
Chris@16
|
203 ]
|
Chris@16
|
204 | ch_p('r') // CR
|
Chris@16
|
205 [
|
Chris@16
|
206 impl::compose(self.value, self.long_lit,
|
Chris@16
|
207 phx::var(self.overflow), phx::val(0x0d))
|
Chris@16
|
208 ]
|
Chris@16
|
209 | ch_p('?')
|
Chris@16
|
210 [
|
Chris@16
|
211 impl::compose(self.value, self.long_lit,
|
Chris@16
|
212 phx::var(self.overflow), phx::val('?'))
|
Chris@16
|
213 ]
|
Chris@16
|
214 | ch_p('\'')
|
Chris@16
|
215 [
|
Chris@16
|
216 impl::compose(self.value, self.long_lit,
|
Chris@16
|
217 phx::var(self.overflow), phx::val('\''))
|
Chris@16
|
218 ]
|
Chris@16
|
219 | ch_p('\"')
|
Chris@16
|
220 [
|
Chris@16
|
221 impl::compose(self.value, self.long_lit,
|
Chris@16
|
222 phx::var(self.overflow), phx::val('\"'))
|
Chris@16
|
223 ]
|
Chris@16
|
224 | ch_p('\\')
|
Chris@16
|
225 [
|
Chris@16
|
226 impl::compose(self.value, self.long_lit,
|
Chris@16
|
227 phx::var(self.overflow), phx::val('\\'))
|
Chris@16
|
228 ]
|
Chris@16
|
229 | ch_p('x')
|
Chris@16
|
230 >> if_p(self.long_lit)
|
Chris@16
|
231 [
|
Chris@16
|
232 hex_wchar_parser_type()
|
Chris@16
|
233 [
|
Chris@16
|
234 impl::compose(self.value, self.long_lit,
|
Chris@16
|
235 phx::var(self.overflow), phx::arg1)
|
Chris@16
|
236 ]
|
Chris@16
|
237 ]
|
Chris@16
|
238 .else_p
|
Chris@16
|
239 [
|
Chris@16
|
240 hex_char_parser_type()
|
Chris@16
|
241 [
|
Chris@16
|
242 impl::compose(self.value, self.long_lit,
|
Chris@16
|
243 phx::var(self.overflow), phx::arg1)
|
Chris@16
|
244 ]
|
Chris@16
|
245 ]
|
Chris@16
|
246 | ch_p('u')
|
Chris@16
|
247 >> uint_parser<unsigned int, 16, 4, 4>()
|
Chris@16
|
248 [
|
Chris@16
|
249 impl::compose(self.value, self.long_lit,
|
Chris@16
|
250 phx::var(self.overflow), phx::arg1)
|
Chris@16
|
251 ]
|
Chris@16
|
252 | ch_p('U')
|
Chris@16
|
253 >> uint_parser<unsigned int, 16, 8, 8>()
|
Chris@16
|
254 [
|
Chris@16
|
255 impl::compose(self.value, self.long_lit,
|
Chris@16
|
256 phx::var(self.overflow), phx::arg1)
|
Chris@16
|
257 ]
|
Chris@16
|
258 | uint_parser<unsigned int, 8, 1, 3>()
|
Chris@16
|
259 [
|
Chris@16
|
260 impl::compose(self.value, self.long_lit,
|
Chris@16
|
261 phx::var(self.overflow), phx::arg1)
|
Chris@16
|
262 ]
|
Chris@16
|
263 )
|
Chris@16
|
264 )
|
Chris@16
|
265 | ~eps_p(ch_p('\'')) >> anychar_p
|
Chris@16
|
266 [
|
Chris@16
|
267 impl::compose(self.value, self.long_lit,
|
Chris@16
|
268 phx::var(self.overflow), phx::arg1)
|
Chris@16
|
269 ]
|
Chris@16
|
270 )
|
Chris@16
|
271 >> ch_p('\'')
|
Chris@16
|
272 ;
|
Chris@16
|
273
|
Chris@16
|
274 BOOST_SPIRIT_DEBUG_TRACE_RULE(ch_lit, TRACE_CHLIT_GRAMMAR);
|
Chris@16
|
275 }
|
Chris@16
|
276
|
Chris@16
|
277 // start rule of this grammar
|
Chris@16
|
278 rule_t const& start() const
|
Chris@16
|
279 { return ch_lit; }
|
Chris@16
|
280 };
|
Chris@16
|
281
|
Chris@16
|
282 // flag signaling integer overflow during value composition
|
Chris@16
|
283 mutable bool overflow;
|
Chris@16
|
284 };
|
Chris@16
|
285
|
Chris@16
|
286 #undef TRACE_CHLIT_GRAMMAR
|
Chris@16
|
287
|
Chris@16
|
288 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
289 //
|
Chris@16
|
290 // The following function is defined here, to allow the separation of
|
Chris@16
|
291 // the compilation of the intlit_grammap from the function using it.
|
Chris@16
|
292 //
|
Chris@16
|
293 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
294
|
Chris@16
|
295 #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0
|
Chris@16
|
296 #define BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE
|
Chris@16
|
297 #else
|
Chris@16
|
298 #define BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE inline
|
Chris@16
|
299 #endif
|
Chris@16
|
300
|
Chris@16
|
301 template <typename IntegralResult, typename TokenT>
|
Chris@16
|
302 BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE
|
Chris@16
|
303 IntegralResult
|
Chris@16
|
304 chlit_grammar_gen<IntegralResult, TokenT>::evaluate(TokenT const &token, value_error &status)
|
Chris@16
|
305 {
|
Chris@16
|
306 using namespace boost::spirit::classic;
|
Chris@16
|
307
|
Chris@16
|
308 chlit_grammar g;
|
Chris@16
|
309 IntegralResult result = 0;
|
Chris@16
|
310 typename TokenT::string_type const &token_val = token.get_value();
|
Chris@16
|
311 parse_info<typename TokenT::string_type::const_iterator> hit =
|
Chris@16
|
312 parse(token_val.begin(), token_val.end(), g[spirit_assign_actor(result)]);
|
Chris@16
|
313
|
Chris@16
|
314 if (!hit.hit) {
|
Chris@16
|
315 BOOST_WAVE_THROW(preprocess_exception, ill_formed_character_literal,
|
Chris@16
|
316 token_val.c_str(), token.get_position());
|
Chris@16
|
317 }
|
Chris@16
|
318 else {
|
Chris@16
|
319 // range check
|
Chris@16
|
320 if ('L' == token_val[0]) {
|
Chris@16
|
321 // recognized wide character
|
Chris@16
|
322 if (g.overflow ||
|
Chris@16
|
323 result > (IntegralResult)(std::numeric_limits<wchar_t>::max)())
|
Chris@16
|
324 {
|
Chris@16
|
325 // out of range
|
Chris@16
|
326 status = error_character_overflow;
|
Chris@16
|
327 }
|
Chris@16
|
328 }
|
Chris@16
|
329 else {
|
Chris@16
|
330 // recognized narrow ('normal') character
|
Chris@16
|
331 if (g.overflow ||
|
Chris@16
|
332 result > (IntegralResult)(std::numeric_limits<unsigned char>::max)())
|
Chris@16
|
333 {
|
Chris@16
|
334 // out of range
|
Chris@16
|
335 status = error_character_overflow;
|
Chris@16
|
336 }
|
Chris@16
|
337 }
|
Chris@16
|
338 }
|
Chris@16
|
339 return result;
|
Chris@16
|
340 }
|
Chris@16
|
341
|
Chris@16
|
342 #undef BOOST_WAVE_CHLITGRAMMAR_GEN_INLINE
|
Chris@16
|
343
|
Chris@16
|
344 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
345 } // namespace grammars
|
Chris@16
|
346 } // namespace wave
|
Chris@16
|
347 } // namespace boost
|
Chris@16
|
348
|
Chris@16
|
349 // the suffix header occurs after all of the code
|
Chris@16
|
350 #ifdef BOOST_HAS_ABI_HEADERS
|
Chris@16
|
351 #include BOOST_ABI_SUFFIX
|
Chris@16
|
352 #endif
|
Chris@16
|
353
|
Chris@16
|
354 #endif // !defined(CPP_CHLIT_GRAMMAR_HPP_9527D349_6592_449A_A409_42A001E6C64C_INCLUDED)
|