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