File indexing completed on 2025-01-31 10:01:55
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_SPIRIT_NUMERICS_IPP
0011 #define BOOST_SPIRIT_NUMERICS_IPP
0012
0013 #include <boost/config/no_tr1/cmath.hpp>
0014 #include <limits>
0015
0016 namespace boost { namespace spirit {
0017
0018 BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
0019
0020 struct sign_parser;
0021
0022 namespace impl
0023 {
0024
0025
0026
0027
0028
0029 template <typename ScannerT>
0030 bool
0031 extract_sign(ScannerT const& scan, std::size_t& count)
0032 {
0033
0034 count = 0;
0035 bool neg = *scan == '-';
0036 if (neg || (*scan == '+'))
0037 {
0038 ++scan;
0039 ++count;
0040 return neg;
0041 }
0042
0043 return false;
0044 }
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057 template<const int Radix>
0058 struct radix_traits;
0059
0060
0061 template<>
0062 struct radix_traits<2>
0063 {
0064 template<typename CharT, typename T>
0065 static bool digit(CharT ch, T& val)
0066 {
0067 val = ch - '0';
0068 return ('0' == ch || '1' == ch);
0069 }
0070 };
0071
0072
0073 template<>
0074 struct radix_traits<8>
0075 {
0076 template<typename CharT, typename T>
0077 static bool digit(CharT ch, T& val)
0078 {
0079 val = ch - '0';
0080 return ('0' <= ch && ch <= '7');
0081 }
0082 };
0083
0084
0085 template<>
0086 struct radix_traits<10>
0087 {
0088 template<typename CharT, typename T>
0089 static bool digit(CharT ch, T& val)
0090 {
0091 val = ch - '0';
0092 return impl::isdigit_(ch);
0093 }
0094 };
0095
0096
0097 template<>
0098 struct radix_traits<16>
0099 {
0100 template<typename CharT, typename T>
0101 static bool digit(CharT ch, T& val)
0102 {
0103 if (radix_traits<10>::digit(ch, val))
0104 return true;
0105
0106 CharT lc = impl::tolower_(ch);
0107 if ('a' <= lc && lc <= 'f')
0108 {
0109 val = lc - 'a' + 10;
0110 return true;
0111 }
0112 return false;
0113 }
0114 };
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154 #if defined(BOOST_MSVC)
0155 #pragma warning(push)
0156 #pragma warning(disable:4127)
0157 #endif
0158
0159 template <typename T, int Radix>
0160 struct positive_accumulate
0161 {
0162
0163 static bool add(T& n, T digit)
0164 {
0165 if (std::numeric_limits<T>::is_specialized)
0166 {
0167 static T const max = (std::numeric_limits<T>::max)();
0168 static T const max_div_radix = max/Radix;
0169
0170 if (n > max_div_radix)
0171 return false;
0172 n *= Radix;
0173
0174 if (n > max - digit)
0175 return false;
0176 n += digit;
0177
0178 return true;
0179 }
0180 else
0181 {
0182 n *= Radix;
0183 n += digit;
0184 return true;
0185 }
0186 }
0187 };
0188
0189 template <typename T, int Radix>
0190 struct negative_accumulate
0191 {
0192
0193 static bool add(T& n, T digit)
0194 {
0195 if (std::numeric_limits<T>::is_specialized)
0196 {
0197 typedef std::numeric_limits<T> num_limits;
0198 static T const min =
0199 (!num_limits::is_integer && num_limits::is_signed && num_limits::has_denorm) ?
0200 -(num_limits::max)() : (num_limits::min)();
0201 static T const min_div_radix = min/Radix;
0202
0203 if (n < min_div_radix)
0204 return false;
0205 n *= Radix;
0206
0207 if (n < min + digit)
0208 return false;
0209 n -= digit;
0210
0211 return true;
0212 }
0213 else
0214 {
0215 n *= Radix;
0216 n -= digit;
0217 return true;
0218 }
0219 }
0220 };
0221
0222 template <int MaxDigits>
0223 inline bool allow_more_digits(std::size_t i)
0224 {
0225 return i < MaxDigits;
0226 }
0227
0228 template <>
0229 inline bool allow_more_digits<-1>(std::size_t)
0230 {
0231 return true;
0232 }
0233
0234
0235 template <
0236 int Radix, unsigned MinDigits, int MaxDigits,
0237 typename Accumulate
0238 >
0239 struct extract_int
0240 {
0241 template <typename ScannerT, typename T>
0242 static bool
0243 f(ScannerT& scan, T& n, std::size_t& count)
0244 {
0245 std::size_t i = 0;
0246 T digit;
0247 while( allow_more_digits<MaxDigits>(i) && !scan.at_end() &&
0248 radix_traits<Radix>::digit(*scan, digit) )
0249 {
0250 if (!Accumulate::add(n, digit))
0251 return false;
0252 ++i, ++scan, ++count;
0253 }
0254 return i >= MinDigits;
0255 }
0256 };
0257
0258
0259
0260
0261
0262
0263 template <
0264 typename T = unsigned,
0265 int Radix = 10,
0266 unsigned MinDigits = 1,
0267 int MaxDigits = -1
0268 >
0269 struct uint_parser_impl
0270 : parser<uint_parser_impl<T, Radix, MinDigits, MaxDigits> >
0271 {
0272 typedef uint_parser_impl<T, Radix, MinDigits, MaxDigits> self_t;
0273
0274 template <typename ScannerT>
0275 struct result
0276 {
0277 typedef typename match_result<ScannerT, T>::type type;
0278 };
0279
0280 template <typename ScannerT>
0281 typename parser_result<self_t, ScannerT>::type
0282 parse(ScannerT const& scan) const
0283 {
0284 if (!scan.at_end())
0285 {
0286 T n = 0;
0287 std::size_t count = 0;
0288 typename ScannerT::iterator_t save = scan.first;
0289 if (extract_int<Radix, MinDigits, MaxDigits,
0290 positive_accumulate<T, Radix> >::f(scan, n, count))
0291 {
0292 return scan.create_match(count, n, save, scan.first);
0293 }
0294
0295 }
0296 return scan.no_match();
0297 }
0298 };
0299
0300
0301
0302
0303
0304
0305 template <
0306 typename T = unsigned,
0307 int Radix = 10,
0308 unsigned MinDigits = 1,
0309 int MaxDigits = -1
0310 >
0311 struct int_parser_impl
0312 : parser<int_parser_impl<T, Radix, MinDigits, MaxDigits> >
0313 {
0314 typedef int_parser_impl<T, Radix, MinDigits, MaxDigits> self_t;
0315
0316 template <typename ScannerT>
0317 struct result
0318 {
0319 typedef typename match_result<ScannerT, T>::type type;
0320 };
0321
0322 template <typename ScannerT>
0323 typename parser_result<self_t, ScannerT>::type
0324 parse(ScannerT const& scan) const
0325 {
0326 typedef extract_int<Radix, MinDigits, MaxDigits,
0327 negative_accumulate<T, Radix> > extract_int_neg_t;
0328 typedef extract_int<Radix, MinDigits, MaxDigits,
0329 positive_accumulate<T, Radix> > extract_int_pos_t;
0330
0331 if (!scan.at_end())
0332 {
0333 T n = 0;
0334 std::size_t count = 0;
0335 typename ScannerT::iterator_t save = scan.first;
0336
0337 bool hit = impl::extract_sign(scan, count);
0338
0339 if (hit)
0340 hit = extract_int_neg_t::f(scan, n, count);
0341 else
0342 hit = extract_int_pos_t::f(scan, n, count);
0343
0344 if (hit)
0345 return scan.create_match(count, n, save, scan.first);
0346 else
0347 scan.first = save;
0348
0349 }
0350 return scan.no_match();
0351 }
0352 };
0353
0354
0355
0356
0357
0358
0359 template <typename RT, typename T, typename RealPoliciesT>
0360 struct real_parser_impl
0361 {
0362 typedef real_parser_impl<RT, T, RealPoliciesT> self_t;
0363
0364 template <typename ScannerT>
0365 RT parse_main(ScannerT const& scan) const
0366 {
0367 if (scan.at_end())
0368 return scan.no_match();
0369 typename ScannerT::iterator_t save = scan.first;
0370
0371 typedef typename parser_result<sign_parser, ScannerT>::type
0372 sign_match_t;
0373 typedef typename parser_result<chlit<>, ScannerT>::type
0374 exp_match_t;
0375
0376 sign_match_t sign_match = RealPoliciesT::parse_sign(scan);
0377 std::size_t count = sign_match ? sign_match.length() : 0;
0378 bool neg = sign_match.has_valid_attribute() ?
0379 sign_match.value() : false;
0380
0381 RT n_match = RealPoliciesT::parse_n(scan);
0382 T n = n_match.has_valid_attribute() ?
0383 n_match.value() : T(0);
0384 bool got_a_number = n_match;
0385 exp_match_t e_hit;
0386
0387 if (!got_a_number && !RealPoliciesT::allow_leading_dot)
0388 return scan.no_match();
0389 else
0390 count += n_match.length();
0391
0392 if (neg)
0393 n = -n;
0394
0395 if (RealPoliciesT::parse_dot(scan))
0396 {
0397
0398
0399
0400
0401 if (RT hit = RealPoliciesT::parse_frac_n(scan))
0402 {
0403 #if !defined(BOOST_NO_STDC_NAMESPACE)
0404 using namespace std;
0405 #endif
0406 hit.value(hit.value()
0407 * pow(T(10), T(-hit.length())));
0408 if (neg)
0409 n -= hit.value();
0410 else
0411 n += hit.value();
0412 count += hit.length() + 1;
0413
0414 }
0415
0416 else if (!got_a_number ||
0417 !RealPoliciesT::allow_trailing_dot)
0418 return scan.no_match();
0419
0420 e_hit = RealPoliciesT::parse_exp(scan);
0421 }
0422 else
0423 {
0424
0425
0426
0427 if (!got_a_number)
0428 return scan.no_match();
0429
0430
0431
0432 e_hit = RealPoliciesT::parse_exp(scan);
0433 if (RealPoliciesT::expect_dot && !e_hit)
0434 return scan.no_match();
0435 }
0436
0437 if (e_hit)
0438 {
0439
0440
0441 if (RT e_n_hit = RealPoliciesT::parse_exp_n(scan))
0442 {
0443 #if !defined(BOOST_NO_STDC_NAMESPACE)
0444 using namespace std;
0445 #endif
0446 n *= pow(T(10), T(e_n_hit.value()));
0447 count += e_n_hit.length() + e_hit.length();
0448 }
0449 else
0450 {
0451
0452 return scan.no_match();
0453 }
0454 }
0455
0456 return scan.create_match(count, n, save, scan.first);
0457 }
0458
0459 template <typename ScannerT>
0460 static RT parse(ScannerT const& scan)
0461 {
0462 static self_t this_;
0463 return impl::implicit_lexeme_parse<RT>(this_, scan, scan);
0464 }
0465 };
0466
0467 #if defined(BOOST_MSVC)
0468 #pragma warning(pop)
0469 #endif
0470
0471 }
0472
0473
0474 BOOST_SPIRIT_CLASSIC_NAMESPACE_END
0475
0476 }}
0477
0478 #endif