• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2001-2014 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(BOOST_SPIRIT_X3_EXTRACT_REAL_APRIL_18_2006_0901AM)
10 #define BOOST_SPIRIT_X3_EXTRACT_REAL_APRIL_18_2006_0901AM
11 
12 #include <cmath>
13 #include <boost/limits.hpp>
14 #include <boost/type_traits/is_same.hpp>
15 #include <boost/spirit/home/x3/support/unused.hpp>
16 #include <boost/spirit/home/x3/support/numeric_utils/pow10.hpp>
17 #include <boost/spirit/home/x3/support/numeric_utils/sign.hpp>
18 #include <boost/spirit/home/x3/support/traits/move_to.hpp>
19 #include <boost/assert.hpp>
20 
21 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
22 # pragma warning(push)
23 # pragma warning(disable: 4100)   // 'p': unreferenced formal parameter
24 # pragma warning(disable: 4127)   // conditional expression is constant
25 #endif
26 
27 namespace boost { namespace spirit { namespace x3 { namespace extension
28 {
29     using x3::traits::pow10;
30 
31     template <typename T>
32     inline bool
scale(int exp,T & n)33     scale(int exp, T& n)
34     {
35         constexpr auto max_exp = std::numeric_limits<T>::max_exponent10;
36         constexpr auto min_exp = std::numeric_limits<T>::min_exponent10;
37 
38         if (exp >= 0)
39         {
40             // return false if exp exceeds the max_exp
41             // do this check only for primitive types!
42             if (is_floating_point<T>() && exp > max_exp)
43                 return false;
44             n *= pow10<T>(exp);
45         }
46         else
47         {
48             if (exp < min_exp)
49             {
50                 n /= pow10<T>(-min_exp);
51 
52                 // return false if exp still exceeds the min_exp
53                 // do this check only for primitive types!
54                 exp += -min_exp;
55                 if (is_floating_point<T>() && exp < min_exp)
56                     return false;
57 
58                 n /= pow10<T>(-exp);
59             }
60             else
61             {
62                 n /= pow10<T>(-exp);
63             }
64         }
65         return true;
66     }
67 
68     inline bool
scale(int,unused_type)69     scale(int /*exp*/, unused_type /*n*/)
70     {
71         // no-op for unused_type
72         return true;
73     }
74 
75     template <typename T>
76     inline bool
scale(int exp,int frac,T & n)77     scale(int exp, int frac, T& n)
78     {
79         return scale(exp - frac, n);
80     }
81 
82     inline bool
scale(int,int,unused_type)83     scale(int /*exp*/, int /*frac*/, unused_type /*n*/)
84     {
85         // no-op for unused_type
86         return true;
87     }
88 
89     inline float
negate(bool neg,float n)90     negate(bool neg, float n)
91     {
92         return neg ? x3::changesign(n) : n;
93     }
94 
95     inline double
negate(bool neg,double n)96     negate(bool neg, double n)
97     {
98         return neg ? x3::changesign(n) : n;
99     }
100 
101     inline long double
negate(bool neg,long double n)102     negate(bool neg, long double n)
103     {
104         return neg ? x3::changesign(n) : n;
105     }
106 
107     template <typename T>
108     inline T
negate(bool neg,T const & n)109     negate(bool neg, T const& n)
110     {
111         return neg ? -n : n;
112     }
113 
114     inline unused_type
negate(bool,unused_type n)115     negate(bool /*neg*/, unused_type n)
116     {
117         // no-op for unused_type
118         return n;
119     }
120 }}}}
121 
122 namespace boost { namespace spirit { namespace x3
123 {
124     template <typename T, typename RealPolicies>
125     struct extract_real
126     {
127         template <typename Iterator, typename Attribute>
128         static bool
parseboost::spirit::x3::extract_real129         parse(Iterator& first, Iterator const& last, Attribute& attr,
130             RealPolicies const& p)
131         {
132             if (first == last)
133                 return false;
134             Iterator save = first;
135 
136             // Start by parsing the sign. neg will be true if
137             // we got a "-" sign, false otherwise.
138             bool neg = p.parse_sign(first, last);
139 
140             // Now attempt to parse an integer
141             T n = 0;
142             bool got_a_number = p.parse_n(first, last, n);
143 
144             // If we did not get a number it might be a NaN, Inf or a leading
145             // dot.
146             if (!got_a_number)
147             {
148                 // Check whether the number to parse is a NaN or Inf
149                 if (p.parse_nan(first, last, n) ||
150                     p.parse_inf(first, last, n))
151                 {
152                     // If we got a negative sign, negate the number
153                     traits::move_to(extension::negate(neg, n), attr);
154                     return true;    // got a NaN or Inf, return early
155                 }
156 
157                 // If we did not get a number and our policies do not
158                 // allow a leading dot, fail and return early (no-match)
159                 if (!p.allow_leading_dot)
160                 {
161                     first = save;
162                     return false;
163                 }
164             }
165 
166             bool e_hit = false;
167             Iterator e_pos;
168             int frac_digits = 0;
169 
170             // Try to parse the dot ('.' decimal point)
171             if (p.parse_dot(first, last))
172             {
173                 // We got the decimal point. Now we will try to parse
174                 // the fraction if it is there. If not, it defaults
175                 // to zero (0) only if we already got a number.
176                 Iterator savef = first;
177                 if (p.parse_frac_n(first, last, n))
178                 {
179                     // Optimization note: don't compute frac_digits if T is
180                     // an unused_type. This should be optimized away by the compiler.
181                     if (!is_same<T, unused_type>::value)
182                         frac_digits =
183                             static_cast<int>(std::distance(savef, first));
184                     BOOST_ASSERT(frac_digits >= 0);
185                 }
186                 else if (!got_a_number || !p.allow_trailing_dot)
187                 {
188                     // We did not get a fraction. If we still haven't got a
189                     // number and our policies do not allow a trailing dot,
190                     // return no-match.
191                     first = save;
192                     return false;
193                 }
194 
195                 // Now, let's see if we can parse the exponent prefix
196                 e_pos = first;
197                 e_hit = p.parse_exp(first, last);
198             }
199             else
200             {
201                 // No dot and no number! Return no-match.
202                 if (!got_a_number)
203                 {
204                     first = save;
205                     return false;
206                 }
207 
208                 // If we must expect a dot and we didn't see an exponent
209                 // prefix, return no-match.
210                 e_pos = first;
211                 e_hit = p.parse_exp(first, last);
212                 if (p.expect_dot && !e_hit)
213                 {
214                     first = save;
215                     return false;
216                 }
217             }
218 
219             if (e_hit)
220             {
221                 // We got the exponent prefix. Now we will try to parse the
222                 // actual exponent. It is an error if it is not there.
223                 int exp = 0;
224                 if (p.parse_exp_n(first, last, exp))
225                 {
226                     // Got the exponent value. Scale the number by
227                     // exp-frac_digits.
228                     if (!extension::scale(exp, frac_digits, n))
229                         return false;
230                 }
231                 else
232                 {
233                     // If there is no number, disregard the exponent altogether.
234                     // by resetting 'first' prior to the exponent prefix (e|E)
235                     first = e_pos;
236 
237                     // Scale the number by -frac_digits.
238                     if (!extension::scale(-frac_digits, n))
239                         return false;
240                 }
241             }
242             else if (frac_digits)
243             {
244                 // No exponent found. Scale the number by -frac_digits.
245                 if (!extension::scale(-frac_digits, n))
246                     return false;
247             }
248 
249             // If we got a negative sign, negate the number
250             traits::move_to(extension::negate(neg, n), attr);
251 
252             // Success!!!
253             return true;
254         }
255     };
256 
257 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
258 # pragma warning(pop)
259 #endif
260 
261 }}}
262 
263 #endif
264