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