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