extract_real.hpp 8.1 KB

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