/*============================================================================= Copyright (c) 2001-2011 Joel de Guzman Copyright (c) 2001-2011 Hartmut Kaiser http://spirit.sourceforge.net/ 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(SPIRIT_REAL_IMPL_APRIL_18_2006_0901AM) #define SPIRIT_REAL_IMPL_APRIL_18_2006_0901AM #if defined(_MSC_VER) #pragma once #endif #include #include #include #include #include #include #include #include #include #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) # pragma warning(push) # pragma warning(disable: 4100) // 'p': unreferenced formal parameter # pragma warning(disable: 4127) // conditional expression is constant #endif namespace boost { namespace spirit { namespace traits { using spirit::traits::pow10; namespace detail { template void compensate_roundoff(T& n, AccT acc_n, mpl::true_) { // at the lowest extremes, we compensate for floating point // roundoff errors by doing imprecise computation using T int const comp = 10; n = T((acc_n / comp) * comp); n += T(acc_n % comp); } template void compensate_roundoff(T& n, AccT acc_n, mpl::false_) { // no need to compensate n = acc_n; } template void compensate_roundoff(T& n, AccT acc_n) { compensate_roundoff(n, acc_n, is_integral()); } } template inline bool scale(int exp, T& n, AccT acc_n) { if (exp >= 0) { int max_exp = std::numeric_limits::max_exponent10; // return false if exp exceeds the max_exp // do this check only for primitive types! if (is_floating_point() && exp > max_exp) return false; n = acc_n * pow10(exp); } else { if (exp < std::numeric_limits::min_exponent10) { int min_exp = std::numeric_limits::min_exponent10; detail::compensate_roundoff(n, acc_n); n /= pow10(-min_exp); // return false if exp still exceeds the min_exp // do this check only for primitive types! exp += -min_exp; if (is_floating_point() && exp < min_exp) return false; n /= pow10(-exp); } else { n = T(acc_n) / pow10(-exp); } } return true; } inline bool scale(int /*exp*/, unused_type /*n*/, unused_type /*acc_n*/) { // no-op for unused_type return true; } template inline bool scale(int exp, int frac, T& n, AccT acc_n) { return scale(exp - frac, n, acc_n); } inline bool scale(int /*exp*/, int /*frac*/, unused_type /*n*/) { // no-op for unused_type return true; } inline float negate(bool neg, float n) { return neg ? spirit::detail::changesign(n) : n; } inline double negate(bool neg, double n) { return neg ? spirit::detail::changesign(n) : n; } inline long double negate(bool neg, long double n) { return neg ? spirit::detail::changesign(n) : n; } template inline T negate(bool neg, T const& n) { return neg ? -n : n; } inline unused_type negate(bool /*neg*/, unused_type n) { // no-op for unused_type return n; } template inline bool is_equal_to_one(T const& value) { return value == 1.0; } inline bool is_equal_to_one(unused_type) { // no-op for unused_type return false; } template struct real_accumulator : mpl::identity {}; template <> struct real_accumulator : mpl::identity::least> {}; template <> struct real_accumulator : mpl::identity::least> {}; }}} namespace boost { namespace spirit { namespace qi { namespace detail { template struct real_impl { template static bool parse(Iterator& first, Iterator const& last, Attribute& attr, RealPolicies const& p) { if (first == last) return false; Iterator save = first; // Start by parsing the sign. neg will be true if // we got a "-" sign, false otherwise. bool neg = p.parse_sign(first, last); // Now attempt to parse an integer T n; typename traits::real_accumulator::type acc_n = 0; bool got_a_number = p.parse_n(first, last, acc_n); // If we did not get a number it might be a NaN, Inf or a leading // dot. if (!got_a_number) { // Check whether the number to parse is a NaN or Inf if (p.parse_nan(first, last, n) || p.parse_inf(first, last, n)) { // If we got a negative sign, negate the number traits::assign_to(traits::negate(neg, n), attr); return true; // got a NaN or Inf, return early } // If we did not get a number and our policies do not // allow a leading dot, fail and return early (no-match) if (!p.allow_leading_dot) { first = save; return false; } } bool e_hit = false; Iterator e_pos; int frac_digits = 0; // Try to parse the dot ('.' decimal point) if (p.parse_dot(first, last)) { // We got the decimal point. Now we will try to parse // the fraction if it is there. If not, it defaults // to zero (0) only if we already got a number. if (p.parse_frac_n(first, last, acc_n, frac_digits)) { BOOST_ASSERT(frac_digits >= 0); } else if (!got_a_number || !p.allow_trailing_dot) { // We did not get a fraction. If we still haven't got a // number and our policies do not allow a trailing dot, // return no-match. first = save; return false; } // Now, let's see if we can parse the exponent prefix e_pos = first; e_hit = p.parse_exp(first, last); } else { // No dot and no number! Return no-match. if (!got_a_number) { first = save; return false; } // If we must expect a dot and we didn't see an exponent // prefix, return no-match. e_pos = first; e_hit = p.parse_exp(first, last); if (p.expect_dot && !e_hit) { first = save; return false; } } if (e_hit) { // We got the exponent prefix. Now we will try to parse the // actual exponent. int exp = 0; if (p.parse_exp_n(first, last, exp)) { // Got the exponent value. Scale the number by // exp-frac_digits. if (!traits::scale(exp, frac_digits, n, acc_n)) return false; } else { // If there is no number, disregard the exponent altogether. // by resetting 'first' prior to the exponent prefix (e|E) first = e_pos; // Scale the number by -frac_digits. bool r = traits::scale(-frac_digits, n, acc_n); BOOST_VERIFY(r); } } else if (frac_digits) { // No exponent found. Scale the number by -frac_digits. bool r = traits::scale(-frac_digits, n, acc_n); BOOST_VERIFY(r); } else if (traits::is_equal_to_one(acc_n)) { // There is a chance of having to parse one of the 1.0#... // styles some implementations use for representing NaN or Inf. // Check whether the number to parse is a NaN or Inf if (p.parse_nan(first, last, n) || p.parse_inf(first, last, n)) { // If we got a negative sign, negate the number traits::assign_to(traits::negate(neg, n), attr); return true; // got a NaN or Inf, return immediately } n = static_cast(acc_n); } else { n = static_cast(acc_n); } // If we got a negative sign, negate the number traits::assign_to(traits::negate(neg, n), attr); // Success!!! return true; } }; #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) # pragma warning(pop) #endif }}}} #endif