diff options
Diffstat (limited to 'boost/wave/grammars/cpp_expression_value.hpp')
-rw-r--r-- | boost/wave/grammars/cpp_expression_value.hpp | 883 |
1 files changed, 883 insertions, 0 deletions
diff --git a/boost/wave/grammars/cpp_expression_value.hpp b/boost/wave/grammars/cpp_expression_value.hpp new file mode 100644 index 0000000000..0cd6e13bc1 --- /dev/null +++ b/boost/wave/grammars/cpp_expression_value.hpp @@ -0,0 +1,883 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#if !defined(CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED) +#define CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED + +#if defined (BOOST_SPIRIT_DEBUG) +#include <iostream> +#endif // defined(BOOST_SPIRIT_DEBUG) + +#include <boost/wave/wave_config.hpp> +#include <boost/wave/grammars/cpp_value_error.hpp> // value_error + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace grammars { +namespace closures { + +class closure_value; +inline bool as_bool(closure_value const& v); + +/////////////////////////////////////////////////////////////////////////////// +// +// The closure_value class represents the closure type, which is used for the +// expression grammar. +// +// This class was introduced to allow the expression grammar to respect +// the numeric type of a numeric literal or expression result. +// +/////////////////////////////////////////////////////////////////////////////// +class closure_value { +public: + + enum value_type { + is_int = 1, + is_uint = 2, + is_bool = 3 + }; + + closure_value(value_error valid_ = error_noerror) + : type(is_int), valid(valid_) + { value.i = 0; } + explicit closure_value(int i, value_error valid_ = error_noerror) + : type(is_int), valid(valid_) + { value.i = i; } + explicit closure_value(unsigned int ui, value_error valid_ = error_noerror) + : type(is_uint), valid(valid_) + { value.ui = ui; } + explicit closure_value(int_literal_type i, value_error valid_ = error_noerror) + : type(is_int), valid(valid_) + { value.i = i; } + explicit closure_value(uint_literal_type ui, value_error valid_ = error_noerror) + : type(is_uint), valid(valid_) + { value.ui = ui; } + explicit closure_value(bool b, value_error valid_ = error_noerror) + : type(is_bool), valid(valid_) + { value.b = b; } + + value_type get_type() const { return type; } + value_error is_valid() const { return valid; } + +// explicit conversion + friend int_literal_type as_int(closure_value const& v) + { + switch (v.type) { + case is_uint: return v.value.ui; + case is_bool: return v.value.b ? 1 : 0; + case is_int: break; + } + return v.value.i; + } + friend uint_literal_type as_uint(closure_value const& v) + { + switch (v.type) { + case is_uint: return v.value.ui; + case is_bool: return v.value.b ? 1 : 0; + case is_int: break; + } + return v.value.i; + } + friend int_literal_type as_long(closure_value const& v) + { + switch (v.type) { + case is_uint: return v.value.ui; + case is_bool: return v.value.b ? 1 : 0; + case is_int: break; + } + return v.value.i; + } + friend uint_literal_type as_ulong(closure_value const& v) + { + switch (v.type) { + case is_uint: return v.value.ui; + case is_bool: return v.value.b ? 1 : 0; + case is_int: break; + } + return v.value.i; + } + friend bool as_bool(closure_value const& v) + { + switch (v.type) { + case is_uint: return v.value.ui != 0; + case is_bool: return v.value.b; + case is_int: break; + } + return v.value.i != 0.0; + } + +// assignment + closure_value &operator= (closure_value const &rhs) + { + switch (rhs.get_type()) { + case is_int: + value.i = as_long(rhs); + type = is_int; + break; + + case is_uint: + value.ui = as_ulong(rhs); + type = is_uint; + break; + + case is_bool: + value.b = as_bool(rhs); + type = is_bool; + break; + } + valid = rhs.valid; + return *this; + } + closure_value &operator= (int rhs) + { + type = is_int; + value.i = rhs; + valid = error_noerror; + return *this; + } + closure_value &operator= (unsigned int rhs) + { + type = is_uint; + value.ui = rhs; + valid = error_noerror; + return *this; + } + closure_value &operator= (int_literal_type rhs) + { + type = is_int; + value.i = rhs; + valid = error_noerror; + return *this; + } + closure_value &operator= (uint_literal_type rhs) + { + type = is_uint; + value.ui = rhs; + valid = error_noerror; + return *this; + } + closure_value &operator= (bool rhs) + { + type = is_bool; + value.b = rhs; + valid = error_noerror; + return *this; + } + +// arithmetics + closure_value &operator+= (closure_value const &rhs) + { + switch (type) { + case is_int: + switch(rhs.type) { + case is_bool: + { + int_literal_type result = value.i + as_long(rhs); + if ((rhs.value.i > 0L && value.i > result) || + (rhs.value.i < 0L && value.i < result)) + { + valid = error_integer_overflow; + } + else { + value.i = result; + } + } + break; + + case is_int: + { + int_literal_type result = value.i + rhs.value.i; + if ((rhs.value.i > 0L && value.i > result) || + (rhs.value.i < 0L && value.i < result)) + { + valid = error_integer_overflow; + } + else { + value.i = result; + } + } + break; + + case is_uint: + { + uint_literal_type result = value.ui + rhs.value.ui; + if (result < value.ui) { + valid = error_integer_overflow; + } + else { + value.ui = result; + type = is_uint; + } + } + break; + } + break; + + case is_uint: + { + uint_literal_type result = value.ui + as_ulong(rhs); + if (result < value.ui) { + valid = error_integer_overflow; + } + else { + value.ui = result; + } + } + break; + + case is_bool: + value.i = value.b + as_bool(rhs); + type = is_int; + } + valid = (value_error)(valid | rhs.valid); + return *this; + } + closure_value &operator-= (closure_value const &rhs) + { + switch (type) { + case is_int: + switch(rhs.type) { + case is_bool: + { + int_literal_type result = value.i - as_long(rhs); + if ((rhs.value.i > 0L && result > value.i) || + (rhs.value.i < 0L && result < value.i)) + { + valid = error_integer_overflow; + } + else { + value.i = result; + } + } + break; + + case is_int: + { + int_literal_type result = value.i - rhs.value.i; + if ((rhs.value.i > 0L && result > value.i) || + (rhs.value.i < 0L && result < value.i)) + { + valid = error_integer_overflow; + } + else { + value.i = result; + } + } + break; + + case is_uint: + { + uint_literal_type result = value.ui - rhs.value.ui; + if (result > value.ui) { + valid = error_integer_overflow; + } + else { + value.ui = result; + type = is_uint; + } + } + break; + } + break; + + case is_uint: + switch(rhs.type) { + case is_bool: + { + uint_literal_type result = value.ui - as_ulong(rhs); + if (result > value.ui) + { + valid = error_integer_overflow; + } + else { + value.ui = result; + } + } + break; + + case is_int: + { + uint_literal_type result = value.ui - rhs.value.i; + if ((rhs.value.i > 0L && result > value.ui) || + (rhs.value.i < 0L && result < value.ui)) + { + valid = error_integer_overflow; + } + else { + value.ui = result; + } + } + break; + + case is_uint: + { + uint_literal_type result = value.ui - rhs.value.ui; + if (result > value.ui) { + valid = error_integer_overflow; + } + else { + value.ui = result; + } + } + break; + } + break; + + case is_bool: + value.i = value.b - as_bool(rhs); + type = is_int; + } + valid = (value_error)(valid | rhs.valid); + return *this; + } + closure_value &operator*= (closure_value const &rhs) + { + switch (type) { + case is_int: + switch(rhs.type) { + case is_bool: value.i *= as_long(rhs); break; + case is_int: + { + int_literal_type result = value.i * rhs.value.i; + if (0 != value.i && 0 != rhs.value.i && + (result / value.i != rhs.value.i || + result / rhs.value.i != value.i) + ) + { + valid = error_integer_overflow; + } + else { + value.i = result; + } + } + break; + + case is_uint: + { + uint_literal_type result = value.ui * rhs.value.ui; + if (0 != value.ui && 0 != rhs.value.ui && + (result / value.ui != rhs.value.ui || + result / rhs.value.ui != value.ui) + ) + { + valid = error_integer_overflow; + } + else { + value.ui = result; + type = is_uint; + } + } + break; + } + break; + + case is_uint: + { + uint_literal_type rhs_val = as_ulong(rhs); + uint_literal_type result = value.ui * rhs_val; + if (0 != value.ui && 0 != rhs_val && + (result / value.ui != rhs_val || + result / rhs_val != value.ui) + ) + { + valid = error_integer_overflow; + } + else { + value.ui = result; + type = is_uint; + } + } + break; + + case is_bool: + switch (rhs.type) { + case is_int: + value.i = (value.b ? 1 : 0) * rhs.value.i; + type = is_int; + break; + + case is_uint: + value.ui = (value.b ? 1 : 0) * rhs.value.ui; + type = is_uint; + break; + + case is_bool: + value.b = 0 != ((value.b ? 1 : 0) * (rhs.value.b ? 1 : 0)); + break; + } + } + valid = (value_error)(valid | rhs.valid); + return *this; + } + closure_value &operator/= (closure_value const &rhs) + { + switch (type) { + case is_int: + switch(rhs.type) { + case is_bool: + case is_int: + if (as_long(rhs) != 0) { + if (value.i == -value.i && -1 == rhs.value.i) { + // LONG_MIN / -1 on two's complement + valid = error_integer_overflow; + } + else { + value.i /= as_long(rhs); + } + } + else { + valid = error_division_by_zero; // division by zero + } + break; + + case is_uint: + if (rhs.value.ui != 0) { + value.ui /= rhs.value.ui; + type = is_uint; + } + else { + valid = error_division_by_zero; // division by zero + } + break; + } + break; + + case is_uint: + if (as_ulong(rhs) != 0) + value.ui /= as_ulong(rhs); + else + valid = error_division_by_zero; // division by zero + break; + + case is_bool: + if (as_bool(rhs)) { + switch(rhs.type) { + case is_int: + value.i = (value.b ? 1 : 0) / rhs.value.i; + type = is_int; + break; + + case is_uint: + value.i = (value.b ? 1 : 0) / rhs.value.ui; + type = is_int; + break; + + case is_bool: + break; + } + } + else { + valid = error_division_by_zero; // division by zero + } + } + return *this; + } + closure_value &operator%= (closure_value const &rhs) + { + switch (type) { + case is_int: + switch(rhs.type) { + case is_bool: + case is_int: + if (as_long(rhs) != 0) { + if (value.i == -value.i && -1 == rhs.value.i) { + // LONG_MIN % -1 on two's complement + valid = error_integer_overflow; + } + else { + value.i %= as_long(rhs); + } + } + else { + valid = error_division_by_zero; // division by zero + } + break; + + case is_uint: + if (rhs.value.ui != 0) { + value.ui %= rhs.value.ui; + type = is_uint; + } + else { + valid = error_division_by_zero; // division by zero + } + break; + } + break; + + case is_uint: + if (as_ulong(rhs) != 0) + value.ui %= as_ulong(rhs); + else + valid = error_division_by_zero; // division by zero + break; + + case is_bool: + if (as_bool(rhs)) { + switch(rhs.type) { + case is_int: + value.i = (value.b ? 1 : 0) % rhs.value.i; + type = is_int; + break; + + case is_uint: + value.i = (value.b ? 1 : 0) % rhs.value.ui; + type = is_int; + break; + + case is_bool: + break; + } + } + else { + valid = error_division_by_zero; // division by zero + } + } + return *this; + } + + friend closure_value + operator- (closure_value const &rhs) + { + switch (rhs.type) { + case is_int: + { + int_literal_type value = as_long(rhs); + if (value != 0 && value == -value) + return closure_value(-value, error_integer_overflow); + return closure_value(-value, rhs.valid); + } + + case is_bool: return closure_value(-as_long(rhs), rhs.valid); + case is_uint: break; + } + + int_literal_type value = as_ulong(rhs); + if (value != 0 && value == -value) + return closure_value(-value, error_integer_overflow); + return closure_value(-value, rhs.valid); + } + friend closure_value + operator~ (closure_value const &rhs) + { + return closure_value(~as_ulong(rhs), rhs.valid); + } + friend closure_value + operator! (closure_value const &rhs) + { + switch (rhs.type) { + case is_int: return closure_value(!as_long(rhs), rhs.valid); + case is_bool: return closure_value(!as_bool(rhs), rhs.valid); + case is_uint: break; + } + return closure_value(!as_ulong(rhs), rhs.valid); + } + +// comparison + friend closure_value + operator== (closure_value const &lhs, closure_value const &rhs) + { + bool cmp = false; + switch (lhs.type) { + case is_int: + switch(rhs.type) { + case is_bool: cmp = as_bool(lhs) == rhs.value.b; break; + case is_int: cmp = lhs.value.i == rhs.value.i; break; + case is_uint: cmp = lhs.value.ui == rhs.value.ui; break; + } + break; + + case is_uint: cmp = lhs.value.ui == as_ulong(rhs); break; + case is_bool: cmp = lhs.value.b == as_bool(rhs); break; + } + return closure_value(cmp, (value_error)(lhs.valid | rhs.valid)); + } + friend closure_value + operator!= (closure_value const &lhs, closure_value const &rhs) + { + return closure_value(!as_bool(lhs == rhs), (value_error)(lhs.valid | rhs.valid)); + } + friend closure_value + operator> (closure_value const &lhs, closure_value const &rhs) + { + bool cmp = false; + switch (lhs.type) { + case is_int: + switch(rhs.type) { + case is_bool: cmp = lhs.value.i > as_long(rhs); break; + case is_int: cmp = lhs.value.i > rhs.value.i; break; + case is_uint: cmp = lhs.value.ui > rhs.value.ui; break; + } + break; + + case is_uint: cmp = lhs.value.ui > as_ulong(rhs); break; + case is_bool: cmp = lhs.value.b > as_bool(rhs); break; + } + return closure_value(cmp, (value_error)(lhs.valid | rhs.valid)); + } + friend closure_value + operator< (closure_value const &lhs, closure_value const &rhs) + { + bool cmp = false; + switch (lhs.type) { + case is_int: + switch(rhs.type) { + case is_bool: cmp = lhs.value.i < as_long(rhs); break; + case is_int: cmp = lhs.value.i < rhs.value.i; break; + case is_uint: cmp = lhs.value.ui < rhs.value.ui; break; + } + break; + + case is_uint: cmp = lhs.value.ui < as_ulong(rhs); break; + case is_bool: cmp = as_bool(lhs) < as_bool(rhs); break; + } + return closure_value(cmp, (value_error)(lhs.valid | rhs.valid)); + } + friend closure_value + operator<= (closure_value const &lhs, closure_value const &rhs) + { + return closure_value(!as_bool(lhs > rhs), (value_error)(lhs.valid | rhs.valid)); + } + friend closure_value + operator>= (closure_value const &lhs, closure_value const &rhs) + { + return closure_value(!as_bool(lhs < rhs), (value_error)(lhs.valid | rhs.valid)); + } + + closure_value & + operator<<= (closure_value const &rhs) + { + switch (type) { + case is_bool: + case is_int: + switch (rhs.type) { + case is_bool: + case is_int: + { + int_literal_type shift_by = as_long(rhs); + + if (shift_by > 64) + shift_by = 64; + else if (shift_by < -64) + shift_by = -64; + value.i <<= shift_by; + } + break; + + case is_uint: + { + uint_literal_type shift_by = as_ulong(rhs); + + if (shift_by > 64) + shift_by = 64; + value.ui <<= shift_by; + + // Note: The usual arithmetic conversions are not performed on + // bit shift operations. + } + break; + } + break; + + case is_uint: + switch (rhs.type) { + case is_bool: + case is_int: + { + int_literal_type shift_by = as_long(rhs); + + if (shift_by > 64) + shift_by = 64; + else if (shift_by < -64) + shift_by = -64; + value.ui <<= shift_by; + } + break; + + case is_uint: + { + uint_literal_type shift_by = as_ulong(rhs); + + if (shift_by > 64) + shift_by = 64; + value.ui <<= shift_by; + } + break; + } + } + valid = (value_error)(valid | rhs.valid); + return *this; + } + + closure_value & + operator>>= (closure_value const &rhs) + { + switch (type) { + case is_bool: + case is_int: + switch (rhs.type) { + case is_bool: + case is_int: + { + int_literal_type shift_by = as_long(rhs); + + if (shift_by > 64) + shift_by = 64; + else if (shift_by < -64) + shift_by = -64; + value.i >>= shift_by; + } + break; + + case is_uint: + { + uint_literal_type shift_by = as_ulong(rhs); + + if (shift_by > 64) + shift_by = 64; + value.ui >>= shift_by; + + // Note: The usual arithmetic conversions are not performed on + // bit shift operations. + } + break; + } + break; + + case is_uint: + switch (rhs.type) { + case is_bool: + case is_int: + { + int_literal_type shift_by = as_long(rhs); + + if (shift_by > 64) + shift_by = 64; + else if (shift_by < -64) + shift_by = -64; + value.ui >>= shift_by; + } + break; + + case is_uint: + { + uint_literal_type shift_by = as_ulong(rhs); + + if (shift_by > 64) + shift_by = 64; + value.ui >>= shift_by; + } + break; + } + break; + } + valid = (value_error)(valid | rhs.valid); + return *this; + } + + friend closure_value + operator|| (closure_value const &lhs, closure_value const &rhs) + { + bool result = as_bool(lhs) || as_bool(rhs); + return closure_value(result, (value_error)(lhs.valid | rhs.valid)); + } + + friend closure_value + operator&& (closure_value const &lhs, closure_value const &rhs) + { + bool result = as_bool(lhs) && as_bool(rhs); + return closure_value(result, (value_error)(lhs.valid | rhs.valid)); + } + + friend closure_value + operator| (closure_value const &lhs, closure_value const &rhs) + { + uint_literal_type result = as_ulong(lhs) | as_ulong(rhs); + return closure_value(result, (value_error)(lhs.valid | rhs.valid)); + } + + friend closure_value + operator& (closure_value const &lhs, closure_value const &rhs) + { + uint_literal_type result = as_ulong(lhs) & as_ulong(rhs); + return closure_value(result, (value_error)(lhs.valid | rhs.valid)); + } + + friend closure_value + operator^ (closure_value const &lhs, closure_value const &rhs) + { + uint_literal_type result = as_ulong(lhs) ^ as_ulong(rhs); + return closure_value(result, (value_error)(lhs.valid | rhs.valid)); + } + + // handle the ?: operator + closure_value & + handle_questionmark(closure_value const &cond, closure_value const &val2) + { + switch (type) { + case is_int: + switch (val2.type) { + case is_bool: value.b = as_bool(cond) ? value.b : as_bool(val2); break; + case is_int: value.i = as_bool(cond) ? value.i : as_long(val2); break; + case is_uint: + value.ui = as_bool(cond) ? value.ui : as_ulong(val2); + type = is_uint; // changing type! + break; + } + break; + + case is_uint: value.ui = as_bool(cond) ? value.ui : as_ulong(val2); break; + case is_bool: value.b = as_bool(cond) ? value.b : as_bool(val2); break; + } + valid = as_bool(cond) ? valid : val2.valid; + return *this; + } + +#if defined (BOOST_SPIRIT_DEBUG) + friend std::ostream& + operator<< (std::ostream &o, closure_value const &val) + { + switch (val.type) { + case is_int: o << "int(" << as_long(val) << ")"; break; + case is_uint: o << "unsigned int(" << as_ulong(val) << ")"; break; + case is_bool: o << "bool(" << as_bool(val) << ")"; break; + } + return o; + } +#endif // defined(BOOST_SPIRIT_DEBUG) + +private: + value_type type; + union { + int_literal_type i; + uint_literal_type ui; + bool b; + } value; + value_error valid; +}; + +/////////////////////////////////////////////////////////////////////////////// +} // namespace closures +} // namespace grammars +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // !defined(CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED) |