Initial Commit
This commit is contained in:
@@ -0,0 +1,478 @@
|
||||
/*=============================================================================
|
||||
Copyright (c) 1998-2003 Joel de Guzman
|
||||
Copyright (c) 2001-2003 Hartmut Kaiser
|
||||
http://spirit.sourceforge.net/
|
||||
|
||||
Use, modification and distribution is subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
=============================================================================*/
|
||||
#ifndef BOOST_SPIRIT_NUMERICS_IPP
|
||||
#define BOOST_SPIRIT_NUMERICS_IPP
|
||||
|
||||
#include <boost/config/no_tr1/cmath.hpp>
|
||||
#include <limits>
|
||||
|
||||
namespace boost { namespace spirit {
|
||||
|
||||
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
|
||||
|
||||
struct sign_parser; // forward declaration only
|
||||
|
||||
namespace impl
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Extract the prefix sign (- or +)
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
template <typename ScannerT>
|
||||
bool
|
||||
extract_sign(ScannerT const& scan, std::size_t& count)
|
||||
{
|
||||
// Extract the sign
|
||||
count = 0;
|
||||
bool neg = *scan == '-';
|
||||
if (neg || (*scan == '+'))
|
||||
{
|
||||
++scan;
|
||||
++count;
|
||||
return neg;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Traits class for radix specific number conversion
|
||||
//
|
||||
// Convert a digit from character representation, ch, to binary
|
||||
// representation, returned in val.
|
||||
// Returns whether the conversion was successful.
|
||||
//
|
||||
// template<typename CharT> static bool digit(CharT ch, T& val);
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
template<const int Radix>
|
||||
struct radix_traits;
|
||||
|
||||
////////////////////////////////// Binary
|
||||
template<>
|
||||
struct radix_traits<2>
|
||||
{
|
||||
template<typename CharT, typename T>
|
||||
static bool digit(CharT ch, T& val)
|
||||
{
|
||||
val = ch - '0';
|
||||
return ('0' == ch || '1' == ch);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////// Octal
|
||||
template<>
|
||||
struct radix_traits<8>
|
||||
{
|
||||
template<typename CharT, typename T>
|
||||
static bool digit(CharT ch, T& val)
|
||||
{
|
||||
val = ch - '0';
|
||||
return ('0' <= ch && ch <= '7');
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////// Decimal
|
||||
template<>
|
||||
struct radix_traits<10>
|
||||
{
|
||||
template<typename CharT, typename T>
|
||||
static bool digit(CharT ch, T& val)
|
||||
{
|
||||
val = ch - '0';
|
||||
return impl::isdigit_(ch);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////// Hexadecimal
|
||||
template<>
|
||||
struct radix_traits<16>
|
||||
{
|
||||
template<typename CharT, typename T>
|
||||
static bool digit(CharT ch, T& val)
|
||||
{
|
||||
if (radix_traits<10>::digit(ch, val))
|
||||
return true;
|
||||
|
||||
CharT lc = impl::tolower_(ch);
|
||||
if ('a' <= lc && lc <= 'f')
|
||||
{
|
||||
val = lc - 'a' + 10;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Helper templates for encapsulation of radix specific
|
||||
// conversion of an input string to an integral value.
|
||||
//
|
||||
// main entry point:
|
||||
//
|
||||
// extract_int<Radix, MinDigits, MaxDigits, Accumulate>
|
||||
// ::f(first, last, n, count);
|
||||
//
|
||||
// The template parameter Radix represents the radix of the
|
||||
// number contained in the parsed string. The template
|
||||
// parameter MinDigits specifies the minimum digits to
|
||||
// accept. The template parameter MaxDigits specifies the
|
||||
// maximum digits to parse. A -1 value for MaxDigits will
|
||||
// make it parse an arbitrarilly large number as long as the
|
||||
// numeric type can hold it. Accumulate is either
|
||||
// positive_accumulate<Radix> (default) for parsing positive
|
||||
// numbers or negative_accumulate<Radix> otherwise.
|
||||
// Checking is only performed when std::numeric_limits<T>::
|
||||
// is_specialized is true. Otherwise, there's no way to
|
||||
// do the check.
|
||||
//
|
||||
// scan.first and scan.last are iterators as usual (i.e.
|
||||
// first is mutable and is moved forward when a match is
|
||||
// found), n is a variable that holds the number (passed by
|
||||
// reference). The number of parsed characters is added to
|
||||
// count (also passed by reference)
|
||||
//
|
||||
// NOTE:
|
||||
// Returns a non-match, if the number to parse
|
||||
// overflows (or underflows) the used type.
|
||||
//
|
||||
// BEWARE:
|
||||
// the parameters 'n' and 'count' should be properly
|
||||
// initialized before calling this function.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) //conditional expression is constant
|
||||
#endif
|
||||
|
||||
template <typename T, int Radix>
|
||||
struct positive_accumulate
|
||||
{
|
||||
// Use this accumulator if number is positive
|
||||
static bool add(T& n, T digit)
|
||||
{
|
||||
if (std::numeric_limits<T>::is_specialized)
|
||||
{
|
||||
static T const max = (std::numeric_limits<T>::max)();
|
||||
static T const max_div_radix = max/Radix;
|
||||
|
||||
if (n > max_div_radix)
|
||||
return false;
|
||||
n *= Radix;
|
||||
|
||||
if (n > max - digit)
|
||||
return false;
|
||||
n += digit;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
n *= Radix;
|
||||
n += digit;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, int Radix>
|
||||
struct negative_accumulate
|
||||
{
|
||||
// Use this accumulator if number is negative
|
||||
static bool add(T& n, T digit)
|
||||
{
|
||||
if (std::numeric_limits<T>::is_specialized)
|
||||
{
|
||||
typedef std::numeric_limits<T> num_limits;
|
||||
static T const min =
|
||||
(!num_limits::is_integer && num_limits::is_signed && num_limits::has_denorm) ?
|
||||
-(num_limits::max)() : (num_limits::min)();
|
||||
static T const min_div_radix = min/Radix;
|
||||
|
||||
if (n < min_div_radix)
|
||||
return false;
|
||||
n *= Radix;
|
||||
|
||||
if (n < min + digit)
|
||||
return false;
|
||||
n -= digit;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
n *= Radix;
|
||||
n -= digit;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <int MaxDigits>
|
||||
inline bool allow_more_digits(std::size_t i)
|
||||
{
|
||||
return i < MaxDigits;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool allow_more_digits<-1>(std::size_t)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
template <
|
||||
int Radix, unsigned MinDigits, int MaxDigits,
|
||||
typename Accumulate
|
||||
>
|
||||
struct extract_int
|
||||
{
|
||||
template <typename ScannerT, typename T>
|
||||
static bool
|
||||
f(ScannerT& scan, T& n, std::size_t& count)
|
||||
{
|
||||
std::size_t i = 0;
|
||||
T digit;
|
||||
while( allow_more_digits<MaxDigits>(i) && !scan.at_end() &&
|
||||
radix_traits<Radix>::digit(*scan, digit) )
|
||||
{
|
||||
if (!Accumulate::add(n, digit))
|
||||
return false; // Overflow
|
||||
++i, ++scan, ++count;
|
||||
}
|
||||
return i >= MinDigits;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// uint_parser_impl class
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
template <
|
||||
typename T = unsigned,
|
||||
int Radix = 10,
|
||||
unsigned MinDigits = 1,
|
||||
int MaxDigits = -1
|
||||
>
|
||||
struct uint_parser_impl
|
||||
: parser<uint_parser_impl<T, Radix, MinDigits, MaxDigits> >
|
||||
{
|
||||
typedef uint_parser_impl<T, Radix, MinDigits, MaxDigits> self_t;
|
||||
|
||||
template <typename ScannerT>
|
||||
struct result
|
||||
{
|
||||
typedef typename match_result<ScannerT, T>::type type;
|
||||
};
|
||||
|
||||
template <typename ScannerT>
|
||||
typename parser_result<self_t, ScannerT>::type
|
||||
parse(ScannerT const& scan) const
|
||||
{
|
||||
if (!scan.at_end())
|
||||
{
|
||||
T n = 0;
|
||||
std::size_t count = 0;
|
||||
typename ScannerT::iterator_t save = scan.first;
|
||||
if (extract_int<Radix, MinDigits, MaxDigits,
|
||||
positive_accumulate<T, Radix> >::f(scan, n, count))
|
||||
{
|
||||
return scan.create_match(count, n, save, scan.first);
|
||||
}
|
||||
// return no-match if number overflows
|
||||
}
|
||||
return scan.no_match();
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// int_parser_impl class
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
template <
|
||||
typename T = unsigned,
|
||||
int Radix = 10,
|
||||
unsigned MinDigits = 1,
|
||||
int MaxDigits = -1
|
||||
>
|
||||
struct int_parser_impl
|
||||
: parser<int_parser_impl<T, Radix, MinDigits, MaxDigits> >
|
||||
{
|
||||
typedef int_parser_impl<T, Radix, MinDigits, MaxDigits> self_t;
|
||||
|
||||
template <typename ScannerT>
|
||||
struct result
|
||||
{
|
||||
typedef typename match_result<ScannerT, T>::type type;
|
||||
};
|
||||
|
||||
template <typename ScannerT>
|
||||
typename parser_result<self_t, ScannerT>::type
|
||||
parse(ScannerT const& scan) const
|
||||
{
|
||||
typedef extract_int<Radix, MinDigits, MaxDigits,
|
||||
negative_accumulate<T, Radix> > extract_int_neg_t;
|
||||
typedef extract_int<Radix, MinDigits, MaxDigits,
|
||||
positive_accumulate<T, Radix> > extract_int_pos_t;
|
||||
|
||||
if (!scan.at_end())
|
||||
{
|
||||
T n = 0;
|
||||
std::size_t count = 0;
|
||||
typename ScannerT::iterator_t save = scan.first;
|
||||
|
||||
bool hit = impl::extract_sign(scan, count);
|
||||
|
||||
if (hit)
|
||||
hit = extract_int_neg_t::f(scan, n, count);
|
||||
else
|
||||
hit = extract_int_pos_t::f(scan, n, count);
|
||||
|
||||
if (hit)
|
||||
return scan.create_match(count, n, save, scan.first);
|
||||
else
|
||||
scan.first = save;
|
||||
// return no-match if number overflows or underflows
|
||||
}
|
||||
return scan.no_match();
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// real_parser_impl class
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
template <typename RT, typename T, typename RealPoliciesT>
|
||||
struct real_parser_impl
|
||||
{
|
||||
typedef real_parser_impl<RT, T, RealPoliciesT> self_t;
|
||||
|
||||
template <typename ScannerT>
|
||||
RT parse_main(ScannerT const& scan) const
|
||||
{
|
||||
if (scan.at_end())
|
||||
return scan.no_match();
|
||||
typename ScannerT::iterator_t save = scan.first;
|
||||
|
||||
typedef typename parser_result<sign_parser, ScannerT>::type
|
||||
sign_match_t;
|
||||
typedef typename parser_result<chlit<>, ScannerT>::type
|
||||
exp_match_t;
|
||||
|
||||
sign_match_t sign_match = RealPoliciesT::parse_sign(scan);
|
||||
std::size_t count = sign_match ? sign_match.length() : 0;
|
||||
bool neg = sign_match.has_valid_attribute() ?
|
||||
sign_match.value() : false;
|
||||
|
||||
RT n_match = RealPoliciesT::parse_n(scan);
|
||||
T n = n_match.has_valid_attribute() ?
|
||||
n_match.value() : T(0);
|
||||
bool got_a_number = n_match;
|
||||
exp_match_t e_hit;
|
||||
|
||||
if (!got_a_number && !RealPoliciesT::allow_leading_dot)
|
||||
return scan.no_match();
|
||||
else
|
||||
count += n_match.length();
|
||||
|
||||
if (neg)
|
||||
n = -n;
|
||||
|
||||
if (RealPoliciesT::parse_dot(scan))
|
||||
{
|
||||
// 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.
|
||||
|
||||
if (RT hit = RealPoliciesT::parse_frac_n(scan))
|
||||
{
|
||||
#if !defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using namespace std; // allow for ADL to find pow()
|
||||
#endif
|
||||
hit.value(hit.value()
|
||||
* pow(T(10), T(-hit.length())));
|
||||
if (neg)
|
||||
n -= hit.value();
|
||||
else
|
||||
n += hit.value();
|
||||
count += hit.length() + 1;
|
||||
|
||||
}
|
||||
|
||||
else if (!got_a_number ||
|
||||
!RealPoliciesT::allow_trailing_dot)
|
||||
return scan.no_match();
|
||||
|
||||
e_hit = RealPoliciesT::parse_exp(scan);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have reached a point where we
|
||||
// still haven't seen a number at all.
|
||||
// We return early with a no-match.
|
||||
if (!got_a_number)
|
||||
return scan.no_match();
|
||||
|
||||
// If we must expect a dot and we didn't see
|
||||
// an exponent, return early with a no-match.
|
||||
e_hit = RealPoliciesT::parse_exp(scan);
|
||||
if (RealPoliciesT::expect_dot && !e_hit)
|
||||
return scan.no_match();
|
||||
}
|
||||
|
||||
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.
|
||||
if (RT e_n_hit = RealPoliciesT::parse_exp_n(scan))
|
||||
{
|
||||
#if !defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using namespace std; // allow for ADL to find pow()
|
||||
#endif
|
||||
n *= pow(T(10), T(e_n_hit.value()));
|
||||
count += e_n_hit.length() + e_hit.length();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Oops, no exponent, return a no-match
|
||||
return scan.no_match();
|
||||
}
|
||||
}
|
||||
|
||||
return scan.create_match(count, n, save, scan.first);
|
||||
}
|
||||
|
||||
template <typename ScannerT>
|
||||
static RT parse(ScannerT const& scan)
|
||||
{
|
||||
static self_t this_;
|
||||
return impl::implicit_lexeme_parse<RT>(this_, scan, scan);
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace impl
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
BOOST_SPIRIT_CLASSIC_NAMESPACE_END
|
||||
|
||||
}} // namespace boost::spirit
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user