1 /*=============================================================================
2     Copyright (c) 2001-2011 Joel de Guzman
3     Copyright (c) 2001-2011 Hartmut Kaiser
4     http://spirit.sourceforge.net/
5 
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
11 
12 #if defined(_MSC_VER)
13 #pragma once
14 #endif
15 
16 #include <cmath>
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>
25 
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
30 #endif
31 
32 namespace boost { namespace spirit { namespace traits
33 {
34     using spirit::traits::pow10;
35 
36     namespace detail
37     {
38         template <typename T, typename AccT>
compensate_roundoff(T & n,AccT acc_n,mpl::true_)39         void compensate_roundoff(T& n, AccT acc_n, mpl::true_)
40         {
41             // at the lowest extremes, we compensate for floating point
42             // roundoff errors by doing imprecise computation using T
43             int const comp = 10;
44             n = T((acc_n / comp) * comp);
45             n += T(acc_n % comp);
46         }
47 
48         template <typename T, typename AccT>
compensate_roundoff(T & n,AccT acc_n,mpl::false_)49         void compensate_roundoff(T& n, AccT acc_n, mpl::false_)
50         {
51             // no need to compensate
52             n = acc_n;
53         }
54 
55         template <typename T, typename AccT>
compensate_roundoff(T & n,AccT acc_n)56         void compensate_roundoff(T& n, AccT acc_n)
57         {
58             compensate_roundoff(n, acc_n, is_integral<AccT>());
59         }
60     }
61 
62     template <typename T, typename AccT>
63     inline bool
scale(int exp,T & n,AccT acc_n)64     scale(int exp, T& n, AccT acc_n)
65     {
66         if (exp >= 0)
67         {
68             int max_exp = std::numeric_limits<T>::max_exponent10;
69 
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)
73                 return false;
74             n = acc_n * pow10<T>(exp);
75         }
76         else
77         {
78             if (exp < std::numeric_limits<T>::min_exponent10)
79             {
80                 int min_exp = std::numeric_limits<T>::min_exponent10;
81                 detail::compensate_roundoff(n, acc_n);
82                 n /= pow10<T>(-min_exp);
83 
84                 // return false if (-exp + min_exp) exceeds the -min_exp
85                 // do this check only for primitive types!
86                 if (is_floating_point<T>() && (-exp + min_exp) > -min_exp)
87                     return false;
88 
89                 n /= pow10<T>(-exp + min_exp);
90             }
91             else
92             {
93                 n = T(acc_n) / pow10<T>(-exp);
94             }
95         }
96         return true;
97     }
98 
99     inline bool
scale(int,unused_type,unused_type)100     scale(int /*exp*/, unused_type /*n*/, unused_type /*acc_n*/)
101     {
102         // no-op for unused_type
103         return true;
104     }
105 
106     template <typename T, typename AccT>
107     inline bool
scale(int exp,int frac,T & n,AccT acc_n)108     scale(int exp, int frac, T& n, AccT acc_n)
109     {
110         return scale(exp - frac, n, acc_n);
111     }
112 
113     inline bool
scale(int,int,unused_type)114     scale(int /*exp*/, int /*frac*/, unused_type /*n*/)
115     {
116         // no-op for unused_type
117         return true;
118     }
119 
120     inline float
negate(bool neg,float n)121     negate(bool neg, float n)
122     {
123         return neg ? spirit::detail::changesign(n) : n;
124     }
125 
126     inline double
negate(bool neg,double n)127     negate(bool neg, double n)
128     {
129         return neg ? spirit::detail::changesign(n) : n;
130     }
131 
132     inline long double
negate(bool neg,long double n)133     negate(bool neg, long double n)
134     {
135         return neg ? spirit::detail::changesign(n) : n;
136     }
137 
138     template <typename T>
139     inline T
negate(bool neg,T const & n)140     negate(bool neg, T const& n)
141     {
142         return neg ? -n : n;
143     }
144 
145     inline unused_type
negate(bool,unused_type n)146     negate(bool /*neg*/, unused_type n)
147     {
148         // no-op for unused_type
149         return n;
150     }
151 
152     template <typename T>
153     inline bool
is_equal_to_one(T const & value)154     is_equal_to_one(T const& value)
155     {
156         return value == 1.0;
157     }
158 
159     inline bool
is_equal_to_one(unused_type)160     is_equal_to_one(unused_type)
161     {
162         // no-op for unused_type
163         return false;
164     }
165 
166     template <typename T>
167     struct real_accumulator : mpl::identity<T> {};
168 
169     template <>
170     struct real_accumulator<float>
171         : mpl::identity<uint_t<(sizeof(float)*CHAR_BIT)>::least> {};
172 
173     template <>
174     struct real_accumulator<double>
175         : mpl::identity<uint_t<(sizeof(double)*CHAR_BIT)>::least> {};
176 }}}
177 
178 namespace boost { namespace spirit { namespace qi  { namespace detail
179 {
180     template <typename T, typename RealPolicies>
181     struct real_impl
182     {
183         template <typename Iterator, typename Attribute>
184         static bool
parseboost::spirit::qi::detail::real_impl185         parse(Iterator& first, Iterator const& last, Attribute& attr,
186             RealPolicies const& p)
187         {
188             if (first == last)
189                 return false;
190             Iterator save = first;
191 
192             // Start by parsing the sign. neg will be true if
193             // we got a "-" sign, false otherwise.
194             bool neg = p.parse_sign(first, last);
195 
196             // Now attempt to parse an integer
197             T n;
198 
199             typename traits::real_accumulator<T>::type acc_n = 0;
200             bool got_a_number = p.parse_n(first, last, acc_n);
201 
202             // If we did not get a number it might be a NaN, Inf or a leading
203             // dot.
204             if (!got_a_number)
205             {
206                 // Check whether the number to parse is a NaN or Inf
207                 if (p.parse_nan(first, last, n) ||
208                     p.parse_inf(first, last, n))
209                 {
210                     // If we got a negative sign, negate the number
211                     traits::assign_to(traits::negate(neg, n), attr);
212                     return true;    // got a NaN or Inf, return early
213                 }
214 
215                 // If we did not get a number and our policies do not
216                 // allow a leading dot, fail and return early (no-match)
217                 if (!p.allow_leading_dot)
218                 {
219                     first = save;
220                     return false;
221                 }
222             }
223 
224             bool e_hit = false;
225             Iterator e_pos;
226             int frac_digits = 0;
227 
228             // Try to parse the dot ('.' decimal point)
229             if (p.parse_dot(first, last))
230             {
231                 // We got the decimal point. Now we will try to parse
232                 // the fraction if it is there. If not, it defaults
233                 // to zero (0) only if we already got a number.
234                 if (p.parse_frac_n(first, last, acc_n, frac_digits))
235                 {
236                 }
237                 else if (!got_a_number || !p.allow_trailing_dot)
238                 {
239                     // We did not get a fraction. If we still haven't got a
240                     // number and our policies do not allow a trailing dot,
241                     // return no-match.
242                     first = save;
243                     return false;
244                 }
245 
246                 // Now, let's see if we can parse the exponent prefix
247                 e_pos = first;
248                 e_hit = p.parse_exp(first, last);
249             }
250             else
251             {
252                 // No dot and no number! Return no-match.
253                 if (!got_a_number)
254                 {
255                     first = save;
256                     return false;
257                 }
258 
259                 // If we must expect a dot and we didn't see an exponent
260                 // prefix, return no-match.
261                 e_pos = first;
262                 e_hit = p.parse_exp(first, last);
263                 if (p.expect_dot && !e_hit)
264                 {
265                     first = save;
266                     return false;
267                 }
268             }
269 
270             if (e_hit)
271             {
272                 // We got the exponent prefix. Now we will try to parse the
273                 // actual exponent.
274                 int exp = 0;
275                 if (p.parse_exp_n(first, last, exp))
276                 {
277                     // Got the exponent value. Scale the number by
278                     // exp-frac_digits.
279                     if (!traits::scale(exp, frac_digits, n, acc_n))
280                         return false;
281                 }
282                 else
283                 {
284                     // If there is no number, disregard the exponent altogether.
285                     // by resetting 'first' prior to the exponent prefix (e|E)
286                     first = e_pos;
287                     // Scale the number by -frac_digits.
288                     traits::scale(-frac_digits, n, acc_n);
289                 }
290             }
291             else if (frac_digits)
292             {
293                 // No exponent found. Scale the number by -frac_digits.
294                 traits::scale(-frac_digits, n, acc_n);
295             }
296             else if (traits::is_equal_to_one(acc_n))
297             {
298                 // There is a chance of having to parse one of the 1.0#...
299                 // styles some implementations use for representing NaN or Inf.
300 
301                 // Check whether the number to parse is a NaN or Inf
302                 if (p.parse_nan(first, last, n) ||
303                     p.parse_inf(first, last, n))
304                 {
305                     // If we got a negative sign, negate the number
306                     traits::assign_to(traits::negate(neg, n), attr);
307                     return true;    // got a NaN or Inf, return immediately
308                 }
309 
310                 n = static_cast<T>(acc_n);
311             }
312             else
313             {
314                 n = static_cast<T>(acc_n);
315             }
316 
317             // If we got a negative sign, negate the number
318             traits::assign_to(traits::negate(neg, n), attr);
319 
320             // Success!!!
321             return true;
322         }
323     };
324 
325 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
326 # pragma warning(pop)
327 #endif
328 
329 }}}}
330 
331 #endif
332