summaryrefslogtreecommitdiff
path: root/boost/spirit/home/qi
diff options
context:
space:
mode:
Diffstat (limited to 'boost/spirit/home/qi')
-rw-r--r--boost/spirit/home/qi/nonterminal/rule.hpp10
-rw-r--r--boost/spirit/home/qi/numeric/detail/numeric_utils.hpp35
-rw-r--r--boost/spirit/home/qi/numeric/detail/real_impl.hpp125
-rw-r--r--boost/spirit/home/qi/numeric/numeric_utils.hpp5
-rw-r--r--boost/spirit/home/qi/numeric/real_policies.hpp18
5 files changed, 143 insertions, 50 deletions
diff --git a/boost/spirit/home/qi/nonterminal/rule.hpp b/boost/spirit/home/qi/nonterminal/rule.hpp
index 8dd42373b0..0901420312 100644
--- a/boost/spirit/home/qi/nonterminal/rule.hpp
+++ b/boost/spirit/home/qi/nonterminal/rule.hpp
@@ -111,16 +111,16 @@ namespace boost { namespace spirit { namespace qi
qi::domain, template_params>::type
skipper_type;
- // The rule's signature
- typedef typename
- spirit::detail::extract_sig<template_params>::type
- sig_type;
-
// The rule's encoding type
typedef typename
spirit::detail::extract_encoding<template_params>::type
encoding_type;
+ // The rule's signature
+ typedef typename
+ spirit::detail::extract_sig<template_params, encoding_type, qi::domain>::type
+ sig_type;
+
// This is the rule's attribute type
typedef typename
spirit::detail::attr_from_sig<sig_type>::type
diff --git a/boost/spirit/home/qi/numeric/detail/numeric_utils.hpp b/boost/spirit/home/qi/numeric/detail/numeric_utils.hpp
index 5137f87f10..7e96a3757f 100644
--- a/boost/spirit/home/qi/numeric/detail/numeric_utils.hpp
+++ b/boost/spirit/home/qi/numeric/detail/numeric_utils.hpp
@@ -2,7 +2,7 @@
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2011 Jan Frederick Eick
- Copyright (c) 2011 Christopher Jefferson
+ Copyright (c) 2011 Christopher Jefferson
Copyright (c) 2006 Stephen Nutt
Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -32,6 +32,11 @@
#include <boost/mpl/and.hpp>
#include <boost/limits.hpp>
+#if defined(BOOST_MSVC)
+# pragma warning(push)
+# pragma warning(disable: 4127) // conditional expression is constant
+#endif
+
#if !defined(SPIRIT_NUMERICS_LOOP_UNROLL)
# define SPIRIT_NUMERICS_LOOP_UNROLL 3
#endif
@@ -132,6 +137,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail
// Ensure n *= Radix will not overflow
static T const max = (std::numeric_limits<T>::max)();
static T const val = max / Radix;
+
if (n > val)
return false;
@@ -181,7 +187,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail
///////////////////////////////////////////////////////////////////////////
// Common code for extract_int::parse specializations
///////////////////////////////////////////////////////////////////////////
- template <unsigned Radix, typename Accumulator, int MaxDigits>
+ template <unsigned Radix, typename Accumulator, int MaxDigits, bool AlwaysCheckOverflow>
struct int_extractor
{
template <typename Char, typename T>
@@ -191,7 +197,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail
static std::size_t const
overflow_free = digits_traits<T, Radix>::value - 1;
- if (count < overflow_free)
+ if (!AlwaysCheckOverflow && (count < overflow_free))
{
Accumulator::add(n, ch, mpl::false_());
}
@@ -267,8 +273,15 @@ namespace boost { namespace spirit { namespace qi { namespace detail
|| it == last) \
break; \
ch = *it; \
- if (!radix_check::is_valid(ch) || !extractor::call(ch, count, val)) \
+ if (!radix_check::is_valid(ch)) \
break; \
+ if (!extractor::call(ch, count, val)) \
+ { \
+ if (IgnoreOverflowDigits) \
+ first = it; \
+ traits::assign_to(val, attr); \
+ return IgnoreOverflowDigits; \
+ } \
++it; \
++count; \
/**/
@@ -277,6 +290,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail
typename T, unsigned Radix, unsigned MinDigits, int MaxDigits
, typename Accumulator = positive_accumulator<Radix>
, bool Accumulate = false
+ , bool IgnoreOverflowDigits = false
>
struct extract_int
{
@@ -292,7 +306,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail
, Attribute& attr)
{
typedef radix_traits<Radix> radix_check;
- typedef int_extractor<Radix, Accumulator, MaxDigits> extractor;
+ typedef int_extractor<Radix, Accumulator, MaxDigits, Accumulate> extractor;
typedef typename
boost::detail::iterator_traits<Iterator>::value_type
char_type;
@@ -370,7 +384,10 @@ namespace boost { namespace spirit { namespace qi { namespace detail
if (!radix_check::is_valid(ch)) \
break; \
if (!extractor::call(ch, count, val)) \
+ { \
+ traits::assign_to(val, attr); \
return false; \
+ } \
++it; \
++count; \
/**/
@@ -390,7 +407,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail
, Attribute& attr)
{
typedef radix_traits<Radix> radix_check;
- typedef int_extractor<Radix, Accumulator, -1> extractor;
+ typedef int_extractor<Radix, Accumulator, -1, Accumulate> extractor;
typedef typename
boost::detail::iterator_traits<Iterator>::value_type
char_type;
@@ -432,7 +449,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail
return true;
}
- count = 0;
+ // count = 0; $$$ verify: I think this is wrong $$$
++it;
while (true)
{
@@ -503,4 +520,8 @@ namespace boost { namespace spirit { namespace qi { namespace detail
};
}}}}
+#if defined(BOOST_MSVC)
+# pragma warning(pop)
+#endif
+
#endif
diff --git a/boost/spirit/home/qi/numeric/detail/real_impl.hpp b/boost/spirit/home/qi/numeric/detail/real_impl.hpp
index a4bd8789b6..cf92712a24 100644
--- a/boost/spirit/home/qi/numeric/detail/real_impl.hpp
+++ b/boost/spirit/home/qi/numeric/detail/real_impl.hpp
@@ -20,6 +20,7 @@
#include <boost/spirit/home/qi/detail/attributes.hpp>
#include <boost/spirit/home/support/detail/pow10.hpp>
#include <boost/spirit/home/support/detail/sign.hpp>
+#include <boost/integer.hpp>
#include <boost/assert.hpp>
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
@@ -31,49 +32,89 @@
namespace boost { namespace spirit { namespace traits
{
using spirit::traits::pow10;
+
+ namespace detail
+ {
+ template <typename T, typename AccT>
+ void compensate_roundoff(T& n, AccT acc_n, mpl::true_)
+ {
+ // at the lowest extremes, we compensate for floating point
+ // roundoff errors by doing imprecise computation using T
+ int const comp = 10;
+ n = T((acc_n / comp) * comp);
+ n += T(acc_n % comp);
+ }
+
+ template <typename T, typename AccT>
+ void compensate_roundoff(T& n, AccT acc_n, mpl::false_)
+ {
+ // no need to compensate
+ n = acc_n;
+ }
+
+ template <typename T, typename AccT>
+ void compensate_roundoff(T& n, AccT acc_n)
+ {
+ compensate_roundoff(n, acc_n, is_integral<AccT>());
+ }
+ }
- template <typename T>
- inline void
- scale(int exp, T& n)
+ template <typename T, typename AccT>
+ inline bool
+ scale(int exp, T& n, AccT acc_n)
{
if (exp >= 0)
{
- // $$$ Why is this failing for boost.math.concepts ? $$$
- //~ int nn = std::numeric_limits<T>::max_exponent10;
- //~ BOOST_ASSERT(exp <= std::numeric_limits<T>::max_exponent10);
- n *= pow10<T>(exp);
+ std::size_t max_exp = std::numeric_limits<T>::max_exponent10;
+
+ // return false if exp exceeds the max_exp
+ // do this check only for primitive types!
+ if (is_floating_point<T>() && exp > max_exp)
+ return false;
+ n = acc_n * pow10<T>(exp);
}
else
{
if (exp < std::numeric_limits<T>::min_exponent10)
{
- n /= pow10<T>(-std::numeric_limits<T>::min_exponent10);
- n /= pow10<T>(-exp + std::numeric_limits<T>::min_exponent10);
+ int min_exp = std::numeric_limits<T>::min_exponent10;
+ detail::compensate_roundoff(n, acc_n);
+ n /= pow10<T>(-min_exp);
+
+ // return false if (-exp + min_exp) exceeds the -min_exp
+ // do this check only for primitive types!
+ if (is_floating_point<T>() && (-exp + min_exp) > -min_exp)
+ return false;
+
+ n /= pow10<T>(-exp + min_exp);
}
else
{
- n /= pow10<T>(-exp);
+ n = T(acc_n) / pow10<T>(-exp);
}
}
+ return true;
}
- inline void
- scale(int /*exp*/, unused_type /*n*/)
+ inline bool
+ scale(int /*exp*/, unused_type /*n*/, unused_type /*acc_n*/)
{
// no-op for unused_type
+ return true;
}
- template <typename T>
- inline void
- scale(int exp, int frac, T& n)
+ template <typename T, typename AccT>
+ inline bool
+ scale(int exp, int frac, T& n, AccT acc_n)
{
- scale(exp - frac, n);
+ return scale(exp - frac, n, acc_n);
}
- inline void
+ inline bool
scale(int /*exp*/, int /*frac*/, unused_type /*n*/)
{
// no-op for unused_type
+ return true;
}
inline float
@@ -121,6 +162,17 @@ namespace boost { namespace spirit { namespace traits
// no-op for unused_type
return false;
}
+
+ template <typename T>
+ struct real_accumulator : mpl::identity<T> {};
+
+ template <>
+ struct real_accumulator<float>
+ : mpl::identity<uint_t<(sizeof(float)*CHAR_BIT)>::least> {};
+
+ template <>
+ struct real_accumulator<double>
+ : mpl::identity<uint_t<(sizeof(double)*CHAR_BIT)>::least> {};
}}}
namespace boost { namespace spirit { namespace qi { namespace detail
@@ -142,8 +194,10 @@ namespace boost { namespace spirit { namespace qi { namespace detail
bool neg = p.parse_sign(first, last);
// Now attempt to parse an integer
- T n = 0;
- bool got_a_number = p.parse_n(first, last, n);
+ T n;
+
+ typename traits::real_accumulator<T>::type acc_n = 0;
+ bool got_a_number = p.parse_n(first, last, acc_n);
// If we did not get a number it might be a NaN, Inf or a leading
// dot.
@@ -168,6 +222,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail
}
bool e_hit = false;
+ Iterator e_pos;
int frac_digits = 0;
// Try to parse the dot ('.' decimal point)
@@ -176,14 +231,8 @@ namespace boost { namespace spirit { namespace qi { namespace detail
// We got the decimal point. Now we will try to parse
// the fraction if it is there. If not, it defaults
// to zero (0) only if we already got a number.
- Iterator savef = first;
- if (p.parse_frac_n(first, last, n))
+ if (p.parse_frac_n(first, last, acc_n, frac_digits))
{
- // Optimization note: don't compute frac_digits if T is
- // an unused_type. This should be optimized away by the compiler.
- if (!is_same<T, unused_type>::value)
- frac_digits =
- static_cast<int>(std::distance(savef, first));
}
else if (!got_a_number || !p.allow_trailing_dot)
{
@@ -195,6 +244,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail
}
// Now, let's see if we can parse the exponent prefix
+ e_pos = first;
e_hit = p.parse_exp(first, last);
}
else
@@ -208,6 +258,7 @@ namespace boost { namespace spirit { namespace qi { namespace detail
// If we must expect a dot and we didn't see an exponent
// prefix, return no-match.
+ e_pos = first;
e_hit = p.parse_exp(first, last);
if (p.expect_dot && !e_hit)
{
@@ -219,27 +270,29 @@ namespace boost { namespace spirit { namespace qi { namespace detail
if (e_hit)
{
// We got the exponent prefix. Now we will try to parse the
- // actual exponent. It is an error if it is not there.
+ // actual exponent.
int exp = 0;
if (p.parse_exp_n(first, last, exp))
{
// Got the exponent value. Scale the number by
// exp-frac_digits.
- traits::scale(exp, frac_digits, n);
+ if (!traits::scale(exp, frac_digits, n, acc_n))
+ return false;
}
else
{
- // Oops, no exponent, return no-match.
- first = save;
- return false;
+ // If there is no number, disregard the exponent altogether.
+ // by resetting 'first' prior to the exponent prefix (e|E)
+ first = e_pos;
+ n = acc_n;
}
}
else if (frac_digits)
{
// No exponent found. Scale the number by -frac_digits.
- traits::scale(-frac_digits, n);
+ traits::scale(-frac_digits, n, acc_n);
}
- else if (traits::is_equal_to_one(n))
+ else if (traits::is_equal_to_one(acc_n))
{
// There is a chance of having to parse one of the 1.0#...
// styles some implementations use for representing NaN or Inf.
@@ -252,6 +305,12 @@ namespace boost { namespace spirit { namespace qi { namespace detail
traits::assign_to(traits::negate(neg, n), attr);
return true; // got a NaN or Inf, return immediately
}
+
+ n = acc_n;
+ }
+ else
+ {
+ n = acc_n;
}
// If we got a negative sign, negate the number
diff --git a/boost/spirit/home/qi/numeric/numeric_utils.hpp b/boost/spirit/home/qi/numeric/numeric_utils.hpp
index eebf40a0fa..c37044a3b6 100644
--- a/boost/spirit/home/qi/numeric/numeric_utils.hpp
+++ b/boost/spirit/home/qi/numeric/numeric_utils.hpp
@@ -44,7 +44,7 @@ namespace boost { namespace spirit { namespace qi
// Low level unsigned integer parser
///////////////////////////////////////////////////////////////////////////
template <typename T, unsigned Radix, unsigned MinDigits, int MaxDigits
- , bool Accumulate = false>
+ , bool Accumulate = false, bool IgnoreOverflowDigits = false>
struct extract_uint
{
// check template parameter 'Radix' for validity
@@ -64,7 +64,8 @@ namespace boost { namespace spirit { namespace qi
, MinDigits
, MaxDigits
, detail::positive_accumulator<Radix>
- , Accumulate>
+ , Accumulate
+ , IgnoreOverflowDigits>
extract_type;
Iterator save = first;
diff --git a/boost/spirit/home/qi/numeric/real_policies.hpp b/boost/spirit/home/qi/numeric/real_policies.hpp
index d4f5654b5b..d73a9dce8a 100644
--- a/boost/spirit/home/qi/numeric/real_policies.hpp
+++ b/boost/spirit/home/qi/numeric/real_policies.hpp
@@ -39,7 +39,7 @@ namespace boost { namespace spirit { namespace qi
static bool
parse_n(Iterator& first, Iterator const& last, Attribute& attr_)
{
- return extract_uint<T, 10, 1, -1>::call(first, last, attr_);
+ return extract_uint<Attribute, 10, 1, -1>::call(first, last, attr_);
}
template <typename Iterator>
@@ -54,9 +54,21 @@ namespace boost { namespace spirit { namespace qi
template <typename Iterator, typename Attribute>
static bool
- parse_frac_n(Iterator& first, Iterator const& last, Attribute& attr_)
+ parse_frac_n(Iterator& first, Iterator const& last, Attribute& attr_, int& frac_digits)
{
- return extract_uint<T, 10, 1, -1, true>::call(first, last, attr_);
+ Iterator savef = first;
+ bool r = extract_uint<Attribute, 10, 1, -1, true, true>::call(first, last, attr_);
+ if (r)
+ {
+ // Optimization note: don't compute frac_digits if T is
+ // an unused_type. This should be optimized away by the compiler.
+ if (!is_same<T, unused_type>::value)
+ frac_digits =
+ static_cast<int>(std::distance(savef, first));
+ // ignore extra (non-significant digits)
+ extract_uint<unused_type, 10, 1, -1>::call(first, last, unused);
+ }
+ return r;
}
template <typename Iterator>