/*============================================================================= | |
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 <cmath> | |
#include <limits> | |
#include <boost/type_traits/is_same.hpp> | |
#include <boost/spirit/home/support/unused.hpp> | |
#include <boost/spirit/home/qi/detail/attributes.hpp> | |
#include <boost/spirit/home/support/detail/pow10.hpp> | |
#include <boost/spirit/home/support/detail/sign.hpp> | |
#include <boost/assert.hpp> | |
#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::detail::pow10; | |
template <typename T> | |
inline void | |
scale(int exp, T& n) | |
{ | |
if (exp >= 0) | |
{ | |
// $$$ Why is this failing for boost.math.concepts ? $$$ | |
//~ int nn = std::numeric_limits<T>::max_exponent10; | |
//~ BOOST_ASSERT(exp <= std::numeric_limits<T>::max_exponent10); | |
n *= pow10<T>(exp); | |
} | |
else | |
{ | |
if (exp < std::numeric_limits<T>::min_exponent10) | |
{ | |
n /= pow10<T>(-std::numeric_limits<T>::min_exponent10); | |
n /= pow10<T>(-exp + std::numeric_limits<T>::min_exponent10); | |
} | |
else | |
{ | |
n /= pow10<T>(-exp); | |
} | |
} | |
} | |
inline void | |
scale(int /*exp*/, unused_type /*n*/) | |
{ | |
// no-op for unused_type | |
} | |
template <typename T> | |
inline void | |
scale(int exp, int frac, T& n) | |
{ | |
scale(exp - frac, n); | |
} | |
inline void | |
scale(int /*exp*/, int /*frac*/, unused_type /*n*/) | |
{ | |
// no-op for unused_type | |
} | |
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 <typename T> | |
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 <typename T> | |
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; | |
} | |
}}} | |
namespace boost { namespace spirit { namespace qi { namespace detail | |
{ | |
template <typename T, typename RealPolicies> | |
struct real_impl | |
{ | |
template <typename Iterator, typename Attribute> | |
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 = 0; | |
bool got_a_number = p.parse_n(first, last, 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; | |
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. | |
Iterator savef = first; | |
if (p.parse_frac_n(first, last, n)) | |
{ | |
// Optimization note: don't compute frac_digits if T is | |
// an unused_type. This should be optimized away by the compiler. | |
if (!is_same<T, unused_type>::value) | |
frac_digits = | |
static_cast<int>(std::distance(savef, first)); | |
} | |
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_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_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. It is an error if it is not there. | |
int exp = 0; | |
if (p.parse_exp_n(first, last, exp)) | |
{ | |
// Got the exponent value. Scale the number by | |
// exp-frac_digits. | |
traits::scale(exp, frac_digits, n); | |
} | |
else | |
{ | |
// Oops, no exponent, return no-match. | |
first = save; | |
return false; | |
} | |
} | |
else if (frac_digits) | |
{ | |
// No exponent found. Scale the number by -frac_digits. | |
traits::scale(-frac_digits, n); | |
} | |
else if (traits::is_equal_to_one(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 | |
} | |
} | |
// 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 |