479 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			479 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| /*=============================================================================
 | |
|     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
 | 
