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_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED)
|
Chris@16
|
12 #define CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED
|
Chris@16
|
13
|
Chris@16
|
14 #if defined (BOOST_SPIRIT_DEBUG)
|
Chris@16
|
15 #include <iostream>
|
Chris@16
|
16 #endif // defined(BOOST_SPIRIT_DEBUG)
|
Chris@16
|
17
|
Chris@16
|
18 #include <boost/wave/wave_config.hpp>
|
Chris@16
|
19 #include <boost/wave/grammars/cpp_value_error.hpp> // value_error
|
Chris@16
|
20
|
Chris@16
|
21 // this must occur after all of the includes and before any code appears
|
Chris@16
|
22 #ifdef BOOST_HAS_ABI_HEADERS
|
Chris@16
|
23 #include BOOST_ABI_PREFIX
|
Chris@16
|
24 #endif
|
Chris@16
|
25
|
Chris@16
|
26 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
27 namespace boost {
|
Chris@16
|
28 namespace wave {
|
Chris@16
|
29 namespace grammars {
|
Chris@16
|
30 namespace closures {
|
Chris@16
|
31
|
Chris@16
|
32 class closure_value;
|
Chris@16
|
33 inline bool as_bool(closure_value const& v);
|
Chris@16
|
34
|
Chris@16
|
35 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
36 //
|
Chris@16
|
37 // The closure_value class represents the closure type, which is used for the
|
Chris@16
|
38 // expression grammar.
|
Chris@16
|
39 //
|
Chris@16
|
40 // This class was introduced to allow the expression grammar to respect
|
Chris@16
|
41 // the numeric type of a numeric literal or expression result.
|
Chris@16
|
42 //
|
Chris@16
|
43 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
44 class closure_value {
|
Chris@16
|
45 public:
|
Chris@16
|
46
|
Chris@16
|
47 enum value_type {
|
Chris@16
|
48 is_int = 1,
|
Chris@16
|
49 is_uint = 2,
|
Chris@16
|
50 is_bool = 3
|
Chris@16
|
51 };
|
Chris@16
|
52
|
Chris@16
|
53 closure_value(value_error valid_ = error_noerror)
|
Chris@16
|
54 : type(is_int), valid(valid_)
|
Chris@16
|
55 { value.i = 0; }
|
Chris@16
|
56 explicit closure_value(int i, value_error valid_ = error_noerror)
|
Chris@16
|
57 : type(is_int), valid(valid_)
|
Chris@16
|
58 { value.i = i; }
|
Chris@16
|
59 explicit closure_value(unsigned int ui, value_error valid_ = error_noerror)
|
Chris@16
|
60 : type(is_uint), valid(valid_)
|
Chris@16
|
61 { value.ui = ui; }
|
Chris@16
|
62 explicit closure_value(int_literal_type i, value_error valid_ = error_noerror)
|
Chris@16
|
63 : type(is_int), valid(valid_)
|
Chris@16
|
64 { value.i = i; }
|
Chris@16
|
65 explicit closure_value(uint_literal_type ui, value_error valid_ = error_noerror)
|
Chris@16
|
66 : type(is_uint), valid(valid_)
|
Chris@16
|
67 { value.ui = ui; }
|
Chris@16
|
68 explicit closure_value(bool b, value_error valid_ = error_noerror)
|
Chris@16
|
69 : type(is_bool), valid(valid_)
|
Chris@16
|
70 { value.b = b; }
|
Chris@16
|
71
|
Chris@16
|
72 value_type get_type() const { return type; }
|
Chris@16
|
73 value_error is_valid() const { return valid; }
|
Chris@16
|
74
|
Chris@16
|
75 // explicit conversion
|
Chris@16
|
76 friend int_literal_type as_int(closure_value const& v)
|
Chris@16
|
77 {
|
Chris@16
|
78 switch (v.type) {
|
Chris@16
|
79 case is_uint: return v.value.ui;
|
Chris@16
|
80 case is_bool: return v.value.b ? 1 : 0;
|
Chris@16
|
81 case is_int: break;
|
Chris@16
|
82 }
|
Chris@16
|
83 return v.value.i;
|
Chris@16
|
84 }
|
Chris@16
|
85 friend uint_literal_type as_uint(closure_value const& v)
|
Chris@16
|
86 {
|
Chris@16
|
87 switch (v.type) {
|
Chris@16
|
88 case is_uint: return v.value.ui;
|
Chris@16
|
89 case is_bool: return v.value.b ? 1 : 0;
|
Chris@16
|
90 case is_int: break;
|
Chris@16
|
91 }
|
Chris@16
|
92 return v.value.i;
|
Chris@16
|
93 }
|
Chris@16
|
94 friend int_literal_type as_long(closure_value const& v)
|
Chris@16
|
95 {
|
Chris@16
|
96 switch (v.type) {
|
Chris@16
|
97 case is_uint: return v.value.ui;
|
Chris@16
|
98 case is_bool: return v.value.b ? 1 : 0;
|
Chris@16
|
99 case is_int: break;
|
Chris@16
|
100 }
|
Chris@16
|
101 return v.value.i;
|
Chris@16
|
102 }
|
Chris@16
|
103 friend uint_literal_type as_ulong(closure_value const& v)
|
Chris@16
|
104 {
|
Chris@16
|
105 switch (v.type) {
|
Chris@16
|
106 case is_uint: return v.value.ui;
|
Chris@16
|
107 case is_bool: return v.value.b ? 1 : 0;
|
Chris@16
|
108 case is_int: break;
|
Chris@16
|
109 }
|
Chris@16
|
110 return v.value.i;
|
Chris@16
|
111 }
|
Chris@16
|
112 friend bool as_bool(closure_value const& v)
|
Chris@16
|
113 {
|
Chris@16
|
114 switch (v.type) {
|
Chris@16
|
115 case is_uint: return v.value.ui != 0;
|
Chris@16
|
116 case is_bool: return v.value.b;
|
Chris@16
|
117 case is_int: break;
|
Chris@16
|
118 }
|
Chris@16
|
119 return v.value.i != 0.0;
|
Chris@16
|
120 }
|
Chris@16
|
121
|
Chris@16
|
122 // assignment
|
Chris@16
|
123 closure_value &operator= (closure_value const &rhs)
|
Chris@16
|
124 {
|
Chris@16
|
125 switch (rhs.get_type()) {
|
Chris@16
|
126 case is_int:
|
Chris@16
|
127 value.i = as_long(rhs);
|
Chris@16
|
128 type = is_int;
|
Chris@16
|
129 break;
|
Chris@16
|
130
|
Chris@16
|
131 case is_uint:
|
Chris@16
|
132 value.ui = as_ulong(rhs);
|
Chris@16
|
133 type = is_uint;
|
Chris@16
|
134 break;
|
Chris@16
|
135
|
Chris@16
|
136 case is_bool:
|
Chris@16
|
137 value.b = as_bool(rhs);
|
Chris@16
|
138 type = is_bool;
|
Chris@16
|
139 break;
|
Chris@16
|
140 }
|
Chris@16
|
141 valid = rhs.valid;
|
Chris@16
|
142 return *this;
|
Chris@16
|
143 }
|
Chris@16
|
144 closure_value &operator= (int rhs)
|
Chris@16
|
145 {
|
Chris@16
|
146 type = is_int;
|
Chris@16
|
147 value.i = rhs;
|
Chris@16
|
148 valid = error_noerror;
|
Chris@16
|
149 return *this;
|
Chris@16
|
150 }
|
Chris@16
|
151 closure_value &operator= (unsigned int rhs)
|
Chris@16
|
152 {
|
Chris@16
|
153 type = is_uint;
|
Chris@16
|
154 value.ui = rhs;
|
Chris@16
|
155 valid = error_noerror;
|
Chris@16
|
156 return *this;
|
Chris@16
|
157 }
|
Chris@16
|
158 closure_value &operator= (int_literal_type rhs)
|
Chris@16
|
159 {
|
Chris@16
|
160 type = is_int;
|
Chris@16
|
161 value.i = rhs;
|
Chris@16
|
162 valid = error_noerror;
|
Chris@16
|
163 return *this;
|
Chris@16
|
164 }
|
Chris@16
|
165 closure_value &operator= (uint_literal_type rhs)
|
Chris@16
|
166 {
|
Chris@16
|
167 type = is_uint;
|
Chris@16
|
168 value.ui = rhs;
|
Chris@16
|
169 valid = error_noerror;
|
Chris@16
|
170 return *this;
|
Chris@16
|
171 }
|
Chris@16
|
172 closure_value &operator= (bool rhs)
|
Chris@16
|
173 {
|
Chris@16
|
174 type = is_bool;
|
Chris@16
|
175 value.b = rhs;
|
Chris@16
|
176 valid = error_noerror;
|
Chris@16
|
177 return *this;
|
Chris@16
|
178 }
|
Chris@16
|
179
|
Chris@16
|
180 // arithmetics
|
Chris@16
|
181 closure_value &operator+= (closure_value const &rhs)
|
Chris@16
|
182 {
|
Chris@16
|
183 switch (type) {
|
Chris@16
|
184 case is_int:
|
Chris@16
|
185 switch(rhs.type) {
|
Chris@16
|
186 case is_bool:
|
Chris@16
|
187 {
|
Chris@16
|
188 int_literal_type result = value.i + as_long(rhs);
|
Chris@16
|
189 if ((rhs.value.i > 0L && value.i > result) ||
|
Chris@16
|
190 (rhs.value.i < 0L && value.i < result))
|
Chris@16
|
191 {
|
Chris@16
|
192 valid = error_integer_overflow;
|
Chris@16
|
193 }
|
Chris@16
|
194 else {
|
Chris@16
|
195 value.i = result;
|
Chris@16
|
196 }
|
Chris@16
|
197 }
|
Chris@16
|
198 break;
|
Chris@16
|
199
|
Chris@16
|
200 case is_int:
|
Chris@16
|
201 {
|
Chris@16
|
202 int_literal_type result = value.i + rhs.value.i;
|
Chris@16
|
203 if ((rhs.value.i > 0L && value.i > result) ||
|
Chris@16
|
204 (rhs.value.i < 0L && value.i < result))
|
Chris@16
|
205 {
|
Chris@16
|
206 valid = error_integer_overflow;
|
Chris@16
|
207 }
|
Chris@16
|
208 else {
|
Chris@16
|
209 value.i = result;
|
Chris@16
|
210 }
|
Chris@16
|
211 }
|
Chris@16
|
212 break;
|
Chris@16
|
213
|
Chris@16
|
214 case is_uint:
|
Chris@16
|
215 {
|
Chris@16
|
216 uint_literal_type result = value.ui + rhs.value.ui;
|
Chris@16
|
217 if (result < value.ui) {
|
Chris@16
|
218 valid = error_integer_overflow;
|
Chris@16
|
219 }
|
Chris@16
|
220 else {
|
Chris@16
|
221 value.ui = result;
|
Chris@16
|
222 type = is_uint;
|
Chris@16
|
223 }
|
Chris@16
|
224 }
|
Chris@16
|
225 break;
|
Chris@16
|
226 }
|
Chris@16
|
227 break;
|
Chris@16
|
228
|
Chris@16
|
229 case is_uint:
|
Chris@16
|
230 {
|
Chris@16
|
231 uint_literal_type result = value.ui + as_ulong(rhs);
|
Chris@16
|
232 if (result < value.ui) {
|
Chris@16
|
233 valid = error_integer_overflow;
|
Chris@16
|
234 }
|
Chris@16
|
235 else {
|
Chris@16
|
236 value.ui = result;
|
Chris@16
|
237 }
|
Chris@16
|
238 }
|
Chris@16
|
239 break;
|
Chris@16
|
240
|
Chris@16
|
241 case is_bool:
|
Chris@16
|
242 value.i = value.b + as_bool(rhs);
|
Chris@16
|
243 type = is_int;
|
Chris@16
|
244 }
|
Chris@16
|
245 valid = (value_error)(valid | rhs.valid);
|
Chris@16
|
246 return *this;
|
Chris@16
|
247 }
|
Chris@16
|
248 closure_value &operator-= (closure_value const &rhs)
|
Chris@16
|
249 {
|
Chris@16
|
250 switch (type) {
|
Chris@16
|
251 case is_int:
|
Chris@16
|
252 switch(rhs.type) {
|
Chris@16
|
253 case is_bool:
|
Chris@16
|
254 {
|
Chris@16
|
255 int_literal_type result = value.i - as_long(rhs);
|
Chris@16
|
256 if ((rhs.value.i > 0L && result > value.i) ||
|
Chris@16
|
257 (rhs.value.i < 0L && result < value.i))
|
Chris@16
|
258 {
|
Chris@16
|
259 valid = error_integer_overflow;
|
Chris@16
|
260 }
|
Chris@16
|
261 else {
|
Chris@16
|
262 value.i = result;
|
Chris@16
|
263 }
|
Chris@16
|
264 }
|
Chris@16
|
265 break;
|
Chris@16
|
266
|
Chris@16
|
267 case is_int:
|
Chris@16
|
268 {
|
Chris@16
|
269 int_literal_type result = value.i - rhs.value.i;
|
Chris@16
|
270 if ((rhs.value.i > 0L && result > value.i) ||
|
Chris@16
|
271 (rhs.value.i < 0L && result < value.i))
|
Chris@16
|
272 {
|
Chris@16
|
273 valid = error_integer_overflow;
|
Chris@16
|
274 }
|
Chris@16
|
275 else {
|
Chris@16
|
276 value.i = result;
|
Chris@16
|
277 }
|
Chris@16
|
278 }
|
Chris@16
|
279 break;
|
Chris@16
|
280
|
Chris@16
|
281 case is_uint:
|
Chris@16
|
282 {
|
Chris@16
|
283 uint_literal_type result = value.ui - rhs.value.ui;
|
Chris@16
|
284 if (result > value.ui) {
|
Chris@16
|
285 valid = error_integer_overflow;
|
Chris@16
|
286 }
|
Chris@16
|
287 else {
|
Chris@16
|
288 value.ui = result;
|
Chris@16
|
289 type = is_uint;
|
Chris@16
|
290 }
|
Chris@16
|
291 }
|
Chris@16
|
292 break;
|
Chris@16
|
293 }
|
Chris@16
|
294 break;
|
Chris@16
|
295
|
Chris@16
|
296 case is_uint:
|
Chris@16
|
297 switch(rhs.type) {
|
Chris@16
|
298 case is_bool:
|
Chris@16
|
299 {
|
Chris@16
|
300 uint_literal_type result = value.ui - as_ulong(rhs);
|
Chris@16
|
301 if (result > value.ui)
|
Chris@16
|
302 {
|
Chris@16
|
303 valid = error_integer_overflow;
|
Chris@16
|
304 }
|
Chris@16
|
305 else {
|
Chris@16
|
306 value.ui = result;
|
Chris@16
|
307 }
|
Chris@16
|
308 }
|
Chris@16
|
309 break;
|
Chris@16
|
310
|
Chris@16
|
311 case is_int:
|
Chris@16
|
312 {
|
Chris@16
|
313 uint_literal_type result = value.ui - rhs.value.i;
|
Chris@16
|
314 if ((rhs.value.i > 0L && result > value.ui) ||
|
Chris@16
|
315 (rhs.value.i < 0L && result < value.ui))
|
Chris@16
|
316 {
|
Chris@16
|
317 valid = error_integer_overflow;
|
Chris@16
|
318 }
|
Chris@16
|
319 else {
|
Chris@16
|
320 value.ui = result;
|
Chris@16
|
321 }
|
Chris@16
|
322 }
|
Chris@16
|
323 break;
|
Chris@16
|
324
|
Chris@16
|
325 case is_uint:
|
Chris@16
|
326 {
|
Chris@16
|
327 uint_literal_type result = value.ui - rhs.value.ui;
|
Chris@16
|
328 if (result > value.ui) {
|
Chris@16
|
329 valid = error_integer_overflow;
|
Chris@16
|
330 }
|
Chris@16
|
331 else {
|
Chris@16
|
332 value.ui = result;
|
Chris@16
|
333 }
|
Chris@16
|
334 }
|
Chris@16
|
335 break;
|
Chris@16
|
336 }
|
Chris@16
|
337 break;
|
Chris@16
|
338
|
Chris@16
|
339 case is_bool:
|
Chris@16
|
340 value.i = value.b - as_bool(rhs);
|
Chris@16
|
341 type = is_int;
|
Chris@16
|
342 }
|
Chris@16
|
343 valid = (value_error)(valid | rhs.valid);
|
Chris@16
|
344 return *this;
|
Chris@16
|
345 }
|
Chris@16
|
346 closure_value &operator*= (closure_value const &rhs)
|
Chris@16
|
347 {
|
Chris@16
|
348 switch (type) {
|
Chris@16
|
349 case is_int:
|
Chris@16
|
350 switch(rhs.type) {
|
Chris@16
|
351 case is_bool: value.i *= as_long(rhs); break;
|
Chris@16
|
352 case is_int:
|
Chris@16
|
353 {
|
Chris@16
|
354 int_literal_type result = value.i * rhs.value.i;
|
Chris@16
|
355 if (0 != value.i && 0 != rhs.value.i &&
|
Chris@16
|
356 (result / value.i != rhs.value.i ||
|
Chris@16
|
357 result / rhs.value.i != value.i)
|
Chris@16
|
358 )
|
Chris@16
|
359 {
|
Chris@16
|
360 valid = error_integer_overflow;
|
Chris@16
|
361 }
|
Chris@16
|
362 else {
|
Chris@16
|
363 value.i = result;
|
Chris@16
|
364 }
|
Chris@16
|
365 }
|
Chris@16
|
366 break;
|
Chris@16
|
367
|
Chris@16
|
368 case is_uint:
|
Chris@16
|
369 {
|
Chris@16
|
370 uint_literal_type result = value.ui * rhs.value.ui;
|
Chris@16
|
371 if (0 != value.ui && 0 != rhs.value.ui &&
|
Chris@16
|
372 (result / value.ui != rhs.value.ui ||
|
Chris@16
|
373 result / rhs.value.ui != value.ui)
|
Chris@16
|
374 )
|
Chris@16
|
375 {
|
Chris@16
|
376 valid = error_integer_overflow;
|
Chris@16
|
377 }
|
Chris@16
|
378 else {
|
Chris@16
|
379 value.ui = result;
|
Chris@16
|
380 type = is_uint;
|
Chris@16
|
381 }
|
Chris@16
|
382 }
|
Chris@16
|
383 break;
|
Chris@16
|
384 }
|
Chris@16
|
385 break;
|
Chris@16
|
386
|
Chris@16
|
387 case is_uint:
|
Chris@16
|
388 {
|
Chris@16
|
389 uint_literal_type rhs_val = as_ulong(rhs);
|
Chris@16
|
390 uint_literal_type result = value.ui * rhs_val;
|
Chris@16
|
391 if (0 != value.ui && 0 != rhs_val &&
|
Chris@16
|
392 (result / value.ui != rhs_val ||
|
Chris@16
|
393 result / rhs_val != value.ui)
|
Chris@16
|
394 )
|
Chris@16
|
395 {
|
Chris@16
|
396 valid = error_integer_overflow;
|
Chris@16
|
397 }
|
Chris@16
|
398 else {
|
Chris@16
|
399 value.ui = result;
|
Chris@16
|
400 type = is_uint;
|
Chris@16
|
401 }
|
Chris@16
|
402 }
|
Chris@16
|
403 break;
|
Chris@16
|
404
|
Chris@16
|
405 case is_bool:
|
Chris@16
|
406 switch (rhs.type) {
|
Chris@16
|
407 case is_int:
|
Chris@16
|
408 value.i = (value.b ? 1 : 0) * rhs.value.i;
|
Chris@16
|
409 type = is_int;
|
Chris@16
|
410 break;
|
Chris@16
|
411
|
Chris@16
|
412 case is_uint:
|
Chris@16
|
413 value.ui = (value.b ? 1 : 0) * rhs.value.ui;
|
Chris@16
|
414 type = is_uint;
|
Chris@16
|
415 break;
|
Chris@16
|
416
|
Chris@16
|
417 case is_bool:
|
Chris@16
|
418 value.b = 0 != ((value.b ? 1 : 0) * (rhs.value.b ? 1 : 0));
|
Chris@16
|
419 break;
|
Chris@16
|
420 }
|
Chris@16
|
421 }
|
Chris@16
|
422 valid = (value_error)(valid | rhs.valid);
|
Chris@16
|
423 return *this;
|
Chris@16
|
424 }
|
Chris@16
|
425 closure_value &operator/= (closure_value const &rhs)
|
Chris@16
|
426 {
|
Chris@16
|
427 switch (type) {
|
Chris@16
|
428 case is_int:
|
Chris@16
|
429 switch(rhs.type) {
|
Chris@16
|
430 case is_bool:
|
Chris@16
|
431 case is_int:
|
Chris@16
|
432 if (as_long(rhs) != 0) {
|
Chris@16
|
433 if (value.i == -value.i && -1 == rhs.value.i) {
|
Chris@16
|
434 // LONG_MIN / -1 on two's complement
|
Chris@16
|
435 valid = error_integer_overflow;
|
Chris@16
|
436 }
|
Chris@16
|
437 else {
|
Chris@16
|
438 value.i /= as_long(rhs);
|
Chris@16
|
439 }
|
Chris@16
|
440 }
|
Chris@16
|
441 else {
|
Chris@16
|
442 valid = error_division_by_zero; // division by zero
|
Chris@16
|
443 }
|
Chris@16
|
444 break;
|
Chris@16
|
445
|
Chris@16
|
446 case is_uint:
|
Chris@16
|
447 if (rhs.value.ui != 0) {
|
Chris@16
|
448 value.ui /= rhs.value.ui;
|
Chris@16
|
449 type = is_uint;
|
Chris@16
|
450 }
|
Chris@16
|
451 else {
|
Chris@16
|
452 valid = error_division_by_zero; // division by zero
|
Chris@16
|
453 }
|
Chris@16
|
454 break;
|
Chris@16
|
455 }
|
Chris@16
|
456 break;
|
Chris@16
|
457
|
Chris@16
|
458 case is_uint:
|
Chris@16
|
459 if (as_ulong(rhs) != 0)
|
Chris@16
|
460 value.ui /= as_ulong(rhs);
|
Chris@16
|
461 else
|
Chris@16
|
462 valid = error_division_by_zero; // division by zero
|
Chris@16
|
463 break;
|
Chris@16
|
464
|
Chris@16
|
465 case is_bool:
|
Chris@16
|
466 if (as_bool(rhs)) {
|
Chris@16
|
467 switch(rhs.type) {
|
Chris@16
|
468 case is_int:
|
Chris@16
|
469 value.i = (value.b ? 1 : 0) / rhs.value.i;
|
Chris@16
|
470 type = is_int;
|
Chris@16
|
471 break;
|
Chris@16
|
472
|
Chris@16
|
473 case is_uint:
|
Chris@16
|
474 value.i = (value.b ? 1 : 0) / rhs.value.ui;
|
Chris@16
|
475 type = is_int;
|
Chris@16
|
476 break;
|
Chris@16
|
477
|
Chris@16
|
478 case is_bool:
|
Chris@16
|
479 break;
|
Chris@16
|
480 }
|
Chris@16
|
481 }
|
Chris@16
|
482 else {
|
Chris@16
|
483 valid = error_division_by_zero; // division by zero
|
Chris@16
|
484 }
|
Chris@16
|
485 }
|
Chris@16
|
486 return *this;
|
Chris@16
|
487 }
|
Chris@16
|
488 closure_value &operator%= (closure_value const &rhs)
|
Chris@16
|
489 {
|
Chris@16
|
490 switch (type) {
|
Chris@16
|
491 case is_int:
|
Chris@16
|
492 switch(rhs.type) {
|
Chris@16
|
493 case is_bool:
|
Chris@16
|
494 case is_int:
|
Chris@16
|
495 if (as_long(rhs) != 0) {
|
Chris@16
|
496 if (value.i == -value.i && -1 == rhs.value.i) {
|
Chris@16
|
497 // LONG_MIN % -1 on two's complement
|
Chris@16
|
498 valid = error_integer_overflow;
|
Chris@16
|
499 }
|
Chris@16
|
500 else {
|
Chris@16
|
501 value.i %= as_long(rhs);
|
Chris@16
|
502 }
|
Chris@16
|
503 }
|
Chris@16
|
504 else {
|
Chris@16
|
505 valid = error_division_by_zero; // division by zero
|
Chris@16
|
506 }
|
Chris@16
|
507 break;
|
Chris@16
|
508
|
Chris@16
|
509 case is_uint:
|
Chris@16
|
510 if (rhs.value.ui != 0) {
|
Chris@16
|
511 value.ui %= rhs.value.ui;
|
Chris@16
|
512 type = is_uint;
|
Chris@16
|
513 }
|
Chris@16
|
514 else {
|
Chris@16
|
515 valid = error_division_by_zero; // division by zero
|
Chris@16
|
516 }
|
Chris@16
|
517 break;
|
Chris@16
|
518 }
|
Chris@16
|
519 break;
|
Chris@16
|
520
|
Chris@16
|
521 case is_uint:
|
Chris@16
|
522 if (as_ulong(rhs) != 0)
|
Chris@16
|
523 value.ui %= as_ulong(rhs);
|
Chris@16
|
524 else
|
Chris@16
|
525 valid = error_division_by_zero; // division by zero
|
Chris@16
|
526 break;
|
Chris@16
|
527
|
Chris@16
|
528 case is_bool:
|
Chris@16
|
529 if (as_bool(rhs)) {
|
Chris@16
|
530 switch(rhs.type) {
|
Chris@16
|
531 case is_int:
|
Chris@16
|
532 value.i = (value.b ? 1 : 0) % rhs.value.i;
|
Chris@16
|
533 type = is_int;
|
Chris@16
|
534 break;
|
Chris@16
|
535
|
Chris@16
|
536 case is_uint:
|
Chris@16
|
537 value.i = (value.b ? 1 : 0) % rhs.value.ui;
|
Chris@16
|
538 type = is_int;
|
Chris@16
|
539 break;
|
Chris@16
|
540
|
Chris@16
|
541 case is_bool:
|
Chris@16
|
542 break;
|
Chris@16
|
543 }
|
Chris@16
|
544 }
|
Chris@16
|
545 else {
|
Chris@16
|
546 valid = error_division_by_zero; // division by zero
|
Chris@16
|
547 }
|
Chris@16
|
548 }
|
Chris@16
|
549 return *this;
|
Chris@16
|
550 }
|
Chris@16
|
551
|
Chris@16
|
552 friend closure_value
|
Chris@16
|
553 operator- (closure_value const &rhs)
|
Chris@16
|
554 {
|
Chris@16
|
555 switch (rhs.type) {
|
Chris@16
|
556 case is_int:
|
Chris@16
|
557 {
|
Chris@16
|
558 int_literal_type value = as_long(rhs);
|
Chris@16
|
559 if (value != 0 && value == -value)
|
Chris@16
|
560 return closure_value(-value, error_integer_overflow);
|
Chris@16
|
561 return closure_value(-value, rhs.valid);
|
Chris@16
|
562 }
|
Chris@16
|
563
|
Chris@16
|
564 case is_bool: return closure_value(-as_long(rhs), rhs.valid);
|
Chris@16
|
565 case is_uint: break;
|
Chris@16
|
566 }
|
Chris@16
|
567
|
Chris@16
|
568 int_literal_type value = as_ulong(rhs);
|
Chris@16
|
569 if (value != 0 && value == -value)
|
Chris@16
|
570 return closure_value(-value, error_integer_overflow);
|
Chris@16
|
571 return closure_value(-value, rhs.valid);
|
Chris@16
|
572 }
|
Chris@16
|
573 friend closure_value
|
Chris@16
|
574 operator~ (closure_value const &rhs)
|
Chris@16
|
575 {
|
Chris@16
|
576 return closure_value(~as_ulong(rhs), rhs.valid);
|
Chris@16
|
577 }
|
Chris@16
|
578 friend closure_value
|
Chris@16
|
579 operator! (closure_value const &rhs)
|
Chris@16
|
580 {
|
Chris@16
|
581 switch (rhs.type) {
|
Chris@16
|
582 case is_int: return closure_value(!as_long(rhs), rhs.valid);
|
Chris@16
|
583 case is_bool: return closure_value(!as_bool(rhs), rhs.valid);
|
Chris@16
|
584 case is_uint: break;
|
Chris@16
|
585 }
|
Chris@16
|
586 return closure_value(!as_ulong(rhs), rhs.valid);
|
Chris@16
|
587 }
|
Chris@16
|
588
|
Chris@16
|
589 // comparison
|
Chris@16
|
590 friend closure_value
|
Chris@16
|
591 operator== (closure_value const &lhs, closure_value const &rhs)
|
Chris@16
|
592 {
|
Chris@16
|
593 bool cmp = false;
|
Chris@16
|
594 switch (lhs.type) {
|
Chris@16
|
595 case is_int:
|
Chris@16
|
596 switch(rhs.type) {
|
Chris@16
|
597 case is_bool: cmp = as_bool(lhs) == rhs.value.b; break;
|
Chris@16
|
598 case is_int: cmp = lhs.value.i == rhs.value.i; break;
|
Chris@16
|
599 case is_uint: cmp = lhs.value.ui == rhs.value.ui; break;
|
Chris@16
|
600 }
|
Chris@16
|
601 break;
|
Chris@16
|
602
|
Chris@16
|
603 case is_uint: cmp = lhs.value.ui == as_ulong(rhs); break;
|
Chris@16
|
604 case is_bool: cmp = lhs.value.b == as_bool(rhs); break;
|
Chris@16
|
605 }
|
Chris@16
|
606 return closure_value(cmp, (value_error)(lhs.valid | rhs.valid));
|
Chris@16
|
607 }
|
Chris@16
|
608 friend closure_value
|
Chris@16
|
609 operator!= (closure_value const &lhs, closure_value const &rhs)
|
Chris@16
|
610 {
|
Chris@16
|
611 return closure_value(!as_bool(lhs == rhs), (value_error)(lhs.valid | rhs.valid));
|
Chris@16
|
612 }
|
Chris@16
|
613 friend closure_value
|
Chris@16
|
614 operator> (closure_value const &lhs, closure_value const &rhs)
|
Chris@16
|
615 {
|
Chris@16
|
616 bool cmp = false;
|
Chris@16
|
617 switch (lhs.type) {
|
Chris@16
|
618 case is_int:
|
Chris@16
|
619 switch(rhs.type) {
|
Chris@16
|
620 case is_bool: cmp = lhs.value.i > as_long(rhs); break;
|
Chris@16
|
621 case is_int: cmp = lhs.value.i > rhs.value.i; break;
|
Chris@16
|
622 case is_uint: cmp = lhs.value.ui > rhs.value.ui; break;
|
Chris@16
|
623 }
|
Chris@16
|
624 break;
|
Chris@16
|
625
|
Chris@16
|
626 case is_uint: cmp = lhs.value.ui > as_ulong(rhs); break;
|
Chris@16
|
627 case is_bool: cmp = lhs.value.b > as_bool(rhs); break;
|
Chris@16
|
628 }
|
Chris@16
|
629 return closure_value(cmp, (value_error)(lhs.valid | rhs.valid));
|
Chris@16
|
630 }
|
Chris@16
|
631 friend closure_value
|
Chris@16
|
632 operator< (closure_value const &lhs, closure_value const &rhs)
|
Chris@16
|
633 {
|
Chris@16
|
634 bool cmp = false;
|
Chris@16
|
635 switch (lhs.type) {
|
Chris@16
|
636 case is_int:
|
Chris@16
|
637 switch(rhs.type) {
|
Chris@16
|
638 case is_bool: cmp = lhs.value.i < as_long(rhs); break;
|
Chris@16
|
639 case is_int: cmp = lhs.value.i < rhs.value.i; break;
|
Chris@16
|
640 case is_uint: cmp = lhs.value.ui < rhs.value.ui; break;
|
Chris@16
|
641 }
|
Chris@16
|
642 break;
|
Chris@16
|
643
|
Chris@16
|
644 case is_uint: cmp = lhs.value.ui < as_ulong(rhs); break;
|
Chris@16
|
645 case is_bool: cmp = as_bool(lhs) < as_bool(rhs); break;
|
Chris@16
|
646 }
|
Chris@16
|
647 return closure_value(cmp, (value_error)(lhs.valid | rhs.valid));
|
Chris@16
|
648 }
|
Chris@16
|
649 friend closure_value
|
Chris@16
|
650 operator<= (closure_value const &lhs, closure_value const &rhs)
|
Chris@16
|
651 {
|
Chris@16
|
652 return closure_value(!as_bool(lhs > rhs), (value_error)(lhs.valid | rhs.valid));
|
Chris@16
|
653 }
|
Chris@16
|
654 friend closure_value
|
Chris@16
|
655 operator>= (closure_value const &lhs, closure_value const &rhs)
|
Chris@16
|
656 {
|
Chris@16
|
657 return closure_value(!as_bool(lhs < rhs), (value_error)(lhs.valid | rhs.valid));
|
Chris@16
|
658 }
|
Chris@16
|
659
|
Chris@16
|
660 closure_value &
|
Chris@16
|
661 operator<<= (closure_value const &rhs)
|
Chris@16
|
662 {
|
Chris@16
|
663 switch (type) {
|
Chris@16
|
664 case is_bool:
|
Chris@16
|
665 case is_int:
|
Chris@16
|
666 switch (rhs.type) {
|
Chris@16
|
667 case is_bool:
|
Chris@16
|
668 case is_int:
|
Chris@16
|
669 {
|
Chris@16
|
670 int_literal_type shift_by = as_long(rhs);
|
Chris@16
|
671
|
Chris@16
|
672 if (shift_by > 64)
|
Chris@16
|
673 shift_by = 64;
|
Chris@16
|
674 else if (shift_by < -64)
|
Chris@16
|
675 shift_by = -64;
|
Chris@16
|
676 value.i <<= shift_by;
|
Chris@16
|
677 }
|
Chris@16
|
678 break;
|
Chris@16
|
679
|
Chris@16
|
680 case is_uint:
|
Chris@16
|
681 {
|
Chris@16
|
682 uint_literal_type shift_by = as_ulong(rhs);
|
Chris@16
|
683
|
Chris@16
|
684 if (shift_by > 64)
|
Chris@16
|
685 shift_by = 64;
|
Chris@16
|
686 value.ui <<= shift_by;
|
Chris@16
|
687
|
Chris@16
|
688 // Note: The usual arithmetic conversions are not performed on
|
Chris@16
|
689 // bit shift operations.
|
Chris@16
|
690 }
|
Chris@16
|
691 break;
|
Chris@16
|
692 }
|
Chris@16
|
693 break;
|
Chris@16
|
694
|
Chris@16
|
695 case is_uint:
|
Chris@16
|
696 switch (rhs.type) {
|
Chris@16
|
697 case is_bool:
|
Chris@16
|
698 case is_int:
|
Chris@16
|
699 {
|
Chris@16
|
700 int_literal_type shift_by = as_long(rhs);
|
Chris@16
|
701
|
Chris@16
|
702 if (shift_by > 64)
|
Chris@16
|
703 shift_by = 64;
|
Chris@16
|
704 else if (shift_by < -64)
|
Chris@16
|
705 shift_by = -64;
|
Chris@16
|
706 value.ui <<= shift_by;
|
Chris@16
|
707 }
|
Chris@16
|
708 break;
|
Chris@16
|
709
|
Chris@16
|
710 case is_uint:
|
Chris@16
|
711 {
|
Chris@16
|
712 uint_literal_type shift_by = as_ulong(rhs);
|
Chris@16
|
713
|
Chris@16
|
714 if (shift_by > 64)
|
Chris@16
|
715 shift_by = 64;
|
Chris@16
|
716 value.ui <<= shift_by;
|
Chris@16
|
717 }
|
Chris@16
|
718 break;
|
Chris@16
|
719 }
|
Chris@16
|
720 }
|
Chris@16
|
721 valid = (value_error)(valid | rhs.valid);
|
Chris@16
|
722 return *this;
|
Chris@16
|
723 }
|
Chris@16
|
724
|
Chris@16
|
725 closure_value &
|
Chris@16
|
726 operator>>= (closure_value const &rhs)
|
Chris@16
|
727 {
|
Chris@16
|
728 switch (type) {
|
Chris@16
|
729 case is_bool:
|
Chris@16
|
730 case is_int:
|
Chris@16
|
731 switch (rhs.type) {
|
Chris@16
|
732 case is_bool:
|
Chris@16
|
733 case is_int:
|
Chris@16
|
734 {
|
Chris@16
|
735 int_literal_type shift_by = as_long(rhs);
|
Chris@16
|
736
|
Chris@16
|
737 if (shift_by > 64)
|
Chris@16
|
738 shift_by = 64;
|
Chris@16
|
739 else if (shift_by < -64)
|
Chris@16
|
740 shift_by = -64;
|
Chris@16
|
741 value.i >>= shift_by;
|
Chris@16
|
742 }
|
Chris@16
|
743 break;
|
Chris@16
|
744
|
Chris@16
|
745 case is_uint:
|
Chris@16
|
746 {
|
Chris@16
|
747 uint_literal_type shift_by = as_ulong(rhs);
|
Chris@16
|
748
|
Chris@16
|
749 if (shift_by > 64)
|
Chris@16
|
750 shift_by = 64;
|
Chris@16
|
751 value.ui >>= shift_by;
|
Chris@16
|
752
|
Chris@16
|
753 // Note: The usual arithmetic conversions are not performed on
|
Chris@16
|
754 // bit shift operations.
|
Chris@16
|
755 }
|
Chris@16
|
756 break;
|
Chris@16
|
757 }
|
Chris@16
|
758 break;
|
Chris@16
|
759
|
Chris@16
|
760 case is_uint:
|
Chris@16
|
761 switch (rhs.type) {
|
Chris@16
|
762 case is_bool:
|
Chris@16
|
763 case is_int:
|
Chris@16
|
764 {
|
Chris@16
|
765 int_literal_type shift_by = as_long(rhs);
|
Chris@16
|
766
|
Chris@16
|
767 if (shift_by > 64)
|
Chris@16
|
768 shift_by = 64;
|
Chris@16
|
769 else if (shift_by < -64)
|
Chris@16
|
770 shift_by = -64;
|
Chris@16
|
771 value.ui >>= shift_by;
|
Chris@16
|
772 }
|
Chris@16
|
773 break;
|
Chris@16
|
774
|
Chris@16
|
775 case is_uint:
|
Chris@16
|
776 {
|
Chris@16
|
777 uint_literal_type shift_by = as_ulong(rhs);
|
Chris@16
|
778
|
Chris@16
|
779 if (shift_by > 64)
|
Chris@16
|
780 shift_by = 64;
|
Chris@16
|
781 value.ui >>= shift_by;
|
Chris@16
|
782 }
|
Chris@16
|
783 break;
|
Chris@16
|
784 }
|
Chris@16
|
785 break;
|
Chris@16
|
786 }
|
Chris@16
|
787 valid = (value_error)(valid | rhs.valid);
|
Chris@16
|
788 return *this;
|
Chris@16
|
789 }
|
Chris@16
|
790
|
Chris@16
|
791 friend closure_value
|
Chris@16
|
792 operator|| (closure_value const &lhs, closure_value const &rhs)
|
Chris@16
|
793 {
|
Chris@16
|
794 bool result = as_bool(lhs) || as_bool(rhs);
|
Chris@16
|
795 return closure_value(result, (value_error)(lhs.valid | rhs.valid));
|
Chris@16
|
796 }
|
Chris@16
|
797
|
Chris@16
|
798 friend closure_value
|
Chris@16
|
799 operator&& (closure_value const &lhs, closure_value const &rhs)
|
Chris@16
|
800 {
|
Chris@16
|
801 bool result = as_bool(lhs) && as_bool(rhs);
|
Chris@16
|
802 return closure_value(result, (value_error)(lhs.valid | rhs.valid));
|
Chris@16
|
803 }
|
Chris@16
|
804
|
Chris@16
|
805 friend closure_value
|
Chris@16
|
806 operator| (closure_value const &lhs, closure_value const &rhs)
|
Chris@16
|
807 {
|
Chris@16
|
808 uint_literal_type result = as_ulong(lhs) | as_ulong(rhs);
|
Chris@16
|
809 return closure_value(result, (value_error)(lhs.valid | rhs.valid));
|
Chris@16
|
810 }
|
Chris@16
|
811
|
Chris@16
|
812 friend closure_value
|
Chris@16
|
813 operator& (closure_value const &lhs, closure_value const &rhs)
|
Chris@16
|
814 {
|
Chris@16
|
815 uint_literal_type result = as_ulong(lhs) & as_ulong(rhs);
|
Chris@16
|
816 return closure_value(result, (value_error)(lhs.valid | rhs.valid));
|
Chris@16
|
817 }
|
Chris@16
|
818
|
Chris@16
|
819 friend closure_value
|
Chris@16
|
820 operator^ (closure_value const &lhs, closure_value const &rhs)
|
Chris@16
|
821 {
|
Chris@16
|
822 uint_literal_type result = as_ulong(lhs) ^ as_ulong(rhs);
|
Chris@16
|
823 return closure_value(result, (value_error)(lhs.valid | rhs.valid));
|
Chris@16
|
824 }
|
Chris@16
|
825
|
Chris@16
|
826 // handle the ?: operator
|
Chris@16
|
827 closure_value &
|
Chris@16
|
828 handle_questionmark(closure_value const &cond, closure_value const &val2)
|
Chris@16
|
829 {
|
Chris@16
|
830 switch (type) {
|
Chris@16
|
831 case is_int:
|
Chris@16
|
832 switch (val2.type) {
|
Chris@16
|
833 case is_bool: value.b = as_bool(cond) ? value.b : as_bool(val2); break;
|
Chris@16
|
834 case is_int: value.i = as_bool(cond) ? value.i : as_long(val2); break;
|
Chris@16
|
835 case is_uint:
|
Chris@16
|
836 value.ui = as_bool(cond) ? value.ui : as_ulong(val2);
|
Chris@16
|
837 type = is_uint; // changing type!
|
Chris@16
|
838 break;
|
Chris@16
|
839 }
|
Chris@16
|
840 break;
|
Chris@16
|
841
|
Chris@16
|
842 case is_uint: value.ui = as_bool(cond) ? value.ui : as_ulong(val2); break;
|
Chris@16
|
843 case is_bool: value.b = as_bool(cond) ? value.b : as_bool(val2); break;
|
Chris@16
|
844 }
|
Chris@16
|
845 valid = as_bool(cond) ? valid : val2.valid;
|
Chris@16
|
846 return *this;
|
Chris@16
|
847 }
|
Chris@16
|
848
|
Chris@16
|
849 #if defined (BOOST_SPIRIT_DEBUG)
|
Chris@16
|
850 friend std::ostream&
|
Chris@16
|
851 operator<< (std::ostream &o, closure_value const &val)
|
Chris@16
|
852 {
|
Chris@16
|
853 switch (val.type) {
|
Chris@16
|
854 case is_int: o << "int(" << as_long(val) << ")"; break;
|
Chris@16
|
855 case is_uint: o << "unsigned int(" << as_ulong(val) << ")"; break;
|
Chris@16
|
856 case is_bool: o << "bool(" << as_bool(val) << ")"; break;
|
Chris@16
|
857 }
|
Chris@16
|
858 return o;
|
Chris@16
|
859 }
|
Chris@16
|
860 #endif // defined(BOOST_SPIRIT_DEBUG)
|
Chris@16
|
861
|
Chris@16
|
862 private:
|
Chris@16
|
863 value_type type;
|
Chris@16
|
864 union {
|
Chris@16
|
865 int_literal_type i;
|
Chris@16
|
866 uint_literal_type ui;
|
Chris@16
|
867 bool b;
|
Chris@16
|
868 } value;
|
Chris@16
|
869 value_error valid;
|
Chris@16
|
870 };
|
Chris@16
|
871
|
Chris@16
|
872 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
873 } // namespace closures
|
Chris@16
|
874 } // namespace grammars
|
Chris@16
|
875 } // namespace wave
|
Chris@16
|
876 } // namespace boost
|
Chris@16
|
877
|
Chris@16
|
878 // the suffix header occurs after all of the code
|
Chris@16
|
879 #ifdef BOOST_HAS_ABI_HEADERS
|
Chris@16
|
880 #include BOOST_ABI_SUFFIX
|
Chris@16
|
881 #endif
|
Chris@16
|
882
|
Chris@16
|
883 #endif // !defined(CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED)
|