/*============================================================================= 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 #include namespace boost { namespace spirit { BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN struct sign_parser; // forward declaration only namespace impl { /////////////////////////////////////////////////////////////////////// // // Extract the prefix sign (- or +) // /////////////////////////////////////////////////////////////////////// template 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 static bool digit(CharT ch, T& val); // /////////////////////////////////////////////////////////////////////// template struct radix_traits; ////////////////////////////////// Binary template<> struct radix_traits<2> { template static bool digit(CharT ch, T& val) { val = ch - '0'; return ('0' == ch || '1' == ch); } }; ////////////////////////////////// Octal template<> struct radix_traits<8> { template static bool digit(CharT ch, T& val) { val = ch - '0'; return ('0' <= ch && ch <= '7'); } }; ////////////////////////////////// Decimal template<> struct radix_traits<10> { template static bool digit(CharT ch, T& val) { val = ch - '0'; return impl::isdigit_(ch); } }; ////////////////////////////////// Hexadecimal template<> struct radix_traits<16> { template 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 // ::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 (default) for parsing positive // numbers or negative_accumulate otherwise. // Checking is only performed when std::numeric_limits:: // 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 struct positive_accumulate { // Use this accumulator if number is positive static bool add(T& n, T digit) { if (std::numeric_limits::is_specialized) { static T const max = (std::numeric_limits::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 struct negative_accumulate { // Use this accumulator if number is negative static bool add(T& n, T digit) { if (std::numeric_limits::is_specialized) { typedef std::numeric_limits 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 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 static bool f(ScannerT& scan, T& n, std::size_t& count) { std::size_t i = 0; T digit; while( allow_more_digits(i) && !scan.at_end() && radix_traits::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 > { typedef uint_parser_impl self_t; template struct result { typedef typename match_result::type type; }; template typename parser_result::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 >::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 > { typedef int_parser_impl self_t; template struct result { typedef typename match_result::type type; }; template typename parser_result::type parse(ScannerT const& scan) const { typedef extract_int > extract_int_neg_t; typedef extract_int > 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 struct real_parser_impl { typedef real_parser_impl self_t; template 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::type sign_match_t; typedef typename parser_result, 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 static RT parse(ScannerT const& scan) { static self_t this_; return impl::implicit_lexeme_parse(this_, scan, scan); } }; #if defined(BOOST_MSVC) #pragma warning(pop) #endif } // namespace impl /////////////////////////////////////////////////////////////////////////////// BOOST_SPIRIT_CLASSIC_NAMESPACE_END }} // namespace boost::spirit #endif