1 /*=============================================================================
2 Copyright (c) 2001-2011 Joel de Guzman
3 Copyright (c) 2001-2011 Hartmut Kaiser
4 http://spirit.sourceforge.net/
6 Distributed under the Boost Software License, Version 1.0. (See accompanying
7 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9 #if !defined(SPIRIT_REAL_IMPL_APRIL_18_2006_0901AM)
10 #define SPIRIT_REAL_IMPL_APRIL_18_2006_0901AM
17 #include <boost/limits.hpp>
18 #include <boost/type_traits/is_same.hpp>
19 #include <boost/spirit/home/support/unused.hpp>
20 #include <boost/spirit/home/qi/detail/attributes.hpp>
21 #include <boost/spirit/home/support/detail/pow10.hpp>
22 #include <boost/spirit/home/support/detail/sign.hpp>
23 #include <boost/integer.hpp>
24 #include <boost/assert.hpp>
26 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
27 # pragma warning(push)
28 # pragma warning(disable: 4100) // 'p': unreferenced formal parameter
29 # pragma warning(disable: 4127) // conditional expression is constant
32 namespace boost { namespace spirit { namespace traits
34 using spirit::traits::pow10;
38 template <typename T, typename AccT>
39 void compensate_roundoff(T& n, AccT acc_n, mpl::true_)
41 // at the lowest extremes, we compensate for floating point
42 // roundoff errors by doing imprecise computation using T
44 n = T((acc_n / comp) * comp);
48 template <typename T, typename AccT>
49 void compensate_roundoff(T& n, AccT acc_n, mpl::false_)
51 // no need to compensate
55 template <typename T, typename AccT>
56 void compensate_roundoff(T& n, AccT acc_n)
58 compensate_roundoff(n, acc_n, is_integral<AccT>());
62 template <typename T, typename AccT>
64 scale(int exp, T& n, AccT acc_n)
68 int max_exp = std::numeric_limits<T>::max_exponent10;
70 // return false if exp exceeds the max_exp
71 // do this check only for primitive types!
72 if (is_floating_point<T>() && exp > max_exp)
74 n = acc_n * pow10<T>(exp);
78 if (exp < std::numeric_limits<T>::min_exponent10)
80 int min_exp = std::numeric_limits<T>::min_exponent10;
81 detail::compensate_roundoff(n, acc_n);
82 n /= pow10<T>(-min_exp);
84 // return false if exp still exceeds the min_exp
85 // do this check only for primitive types!
87 if (is_floating_point<T>() && exp < min_exp)
94 n = T(acc_n) / pow10<T>(-exp);
101 scale(int /*exp*/, unused_type /*n*/, unused_type /*acc_n*/)
103 // no-op for unused_type
107 template <typename T, typename AccT>
109 scale(int exp, int frac, T& n, AccT acc_n)
111 return scale(exp - frac, n, acc_n);
115 scale(int /*exp*/, int /*frac*/, unused_type /*n*/)
117 // no-op for unused_type
122 negate(bool neg, float n)
124 return neg ? spirit::detail::changesign(n) : n;
128 negate(bool neg, double n)
130 return neg ? spirit::detail::changesign(n) : n;
134 negate(bool neg, long double n)
136 return neg ? spirit::detail::changesign(n) : n;
139 template <typename T>
141 negate(bool neg, T const& n)
147 negate(bool /*neg*/, unused_type n)
149 // no-op for unused_type
153 template <typename T>
155 is_equal_to_one(T const& value)
161 is_equal_to_one(unused_type)
163 // no-op for unused_type
167 template <typename T>
168 struct real_accumulator : mpl::identity<T> {};
171 struct real_accumulator<float>
172 : mpl::identity<uint_t<(sizeof(float)*CHAR_BIT)>::least> {};
175 struct real_accumulator<double>
176 : mpl::identity<uint_t<(sizeof(double)*CHAR_BIT)>::least> {};
179 namespace boost { namespace spirit { namespace qi { namespace detail
181 template <typename T, typename RealPolicies>
184 template <typename Iterator, typename Attribute>
186 parse(Iterator& first, Iterator const& last, Attribute& attr,
187 RealPolicies const& p)
191 Iterator save = first;
193 // Start by parsing the sign. neg will be true if
194 // we got a "-" sign, false otherwise.
195 bool neg = p.parse_sign(first, last);
197 // Now attempt to parse an integer
200 typename traits::real_accumulator<T>::type acc_n = 0;
201 bool got_a_number = p.parse_n(first, last, acc_n);
203 // If we did not get a number it might be a NaN, Inf or a leading
207 // Check whether the number to parse is a NaN or Inf
208 if (p.parse_nan(first, last, n) ||
209 p.parse_inf(first, last, n))
211 // If we got a negative sign, negate the number
212 traits::assign_to(traits::negate(neg, n), attr);
213 return true; // got a NaN or Inf, return early
216 // If we did not get a number and our policies do not
217 // allow a leading dot, fail and return early (no-match)
218 if (!p.allow_leading_dot)
229 // Try to parse the dot ('.' decimal point)
230 if (p.parse_dot(first, last))
232 // We got the decimal point. Now we will try to parse
233 // the fraction if it is there. If not, it defaults
234 // to zero (0) only if we already got a number.
235 if (p.parse_frac_n(first, last, acc_n, frac_digits))
237 BOOST_ASSERT(frac_digits >= 0);
239 else if (!got_a_number || !p.allow_trailing_dot)
241 // We did not get a fraction. If we still haven't got a
242 // number and our policies do not allow a trailing dot,
248 // Now, let's see if we can parse the exponent prefix
250 e_hit = p.parse_exp(first, last);
254 // No dot and no number! Return no-match.
261 // If we must expect a dot and we didn't see an exponent
262 // prefix, return no-match.
264 e_hit = p.parse_exp(first, last);
265 if (p.expect_dot && !e_hit)
274 // We got the exponent prefix. Now we will try to parse the
277 if (p.parse_exp_n(first, last, exp))
279 // Got the exponent value. Scale the number by
281 if (!traits::scale(exp, frac_digits, n, acc_n))
286 // If there is no number, disregard the exponent altogether.
287 // by resetting 'first' prior to the exponent prefix (e|E)
289 // Scale the number by -frac_digits.
290 bool r = traits::scale(-frac_digits, n, acc_n);
294 else if (frac_digits)
296 // No exponent found. Scale the number by -frac_digits.
297 bool r = traits::scale(-frac_digits, n, acc_n);
300 else if (traits::is_equal_to_one(acc_n))
302 // There is a chance of having to parse one of the 1.0#...
303 // styles some implementations use for representing NaN or Inf.
305 // Check whether the number to parse is a NaN or Inf
306 if (p.parse_nan(first, last, n) ||
307 p.parse_inf(first, last, n))
309 // If we got a negative sign, negate the number
310 traits::assign_to(traits::negate(neg, n), attr);
311 return true; // got a NaN or Inf, return immediately
314 n = static_cast<T>(acc_n);
318 n = static_cast<T>(acc_n);
321 // If we got a negative sign, negate the number
322 traits::assign_to(traits::negate(neg, n), attr);
329 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
330 # pragma warning(pop)