/*============================================================================= | |
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 |