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