1 | /*=============================================================================
|
---|
2 | Copyright (c) 1998-2003 Joel de Guzman
|
---|
3 | Copyright (c) 2001-2003 Hartmut Kaiser
|
---|
4 | http://spirit.sourceforge.net/
|
---|
5 |
|
---|
6 | Use, modification and distribution is subject to the Boost Software
|
---|
7 | License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
---|
8 | http://www.boost.org/LICENSE_1_0.txt)
|
---|
9 | =============================================================================*/
|
---|
10 | #ifndef BOOST_SPIRIT_NUMERICS_IPP
|
---|
11 | #define BOOST_SPIRIT_NUMERICS_IPP
|
---|
12 |
|
---|
13 | #include <cmath>
|
---|
14 |
|
---|
15 | #if defined(BOOST_NO_STDC_NAMESPACE)
|
---|
16 | # define BOOST_SPIRIT_IMPL_STD_NS
|
---|
17 | #else
|
---|
18 | # define BOOST_SPIRIT_IMPL_STD_NS std
|
---|
19 | #endif
|
---|
20 |
|
---|
21 | namespace boost { namespace spirit {
|
---|
22 |
|
---|
23 | struct sign_parser; // forward declaration only
|
---|
24 |
|
---|
25 | namespace impl
|
---|
26 | {
|
---|
27 | ///////////////////////////////////////////////////////////////////////
|
---|
28 | //
|
---|
29 | // Extract the prefix sign (- or +)
|
---|
30 | //
|
---|
31 | ///////////////////////////////////////////////////////////////////////
|
---|
32 | template <typename ScannerT>
|
---|
33 | bool
|
---|
34 | extract_sign(ScannerT const& scan, std::size_t& count)
|
---|
35 | {
|
---|
36 | // Extract the sign
|
---|
37 | count = 0;
|
---|
38 | bool neg = *scan == '-';
|
---|
39 | if (neg || (*scan == '+'))
|
---|
40 | {
|
---|
41 | ++scan;
|
---|
42 | ++count;
|
---|
43 | return neg;
|
---|
44 | }
|
---|
45 |
|
---|
46 | return false;
|
---|
47 | }
|
---|
48 |
|
---|
49 | ///////////////////////////////////////////////////////////////////////
|
---|
50 | //
|
---|
51 | // Traits class for radix specific number conversion
|
---|
52 | //
|
---|
53 | // Test the validity of a single character:
|
---|
54 | //
|
---|
55 | // template<typename CharT> static bool is_valid(CharT ch);
|
---|
56 | //
|
---|
57 | // Convert a digit from character representation to binary
|
---|
58 | // representation:
|
---|
59 | //
|
---|
60 | // template<typename CharT> static int digit(CharT ch);
|
---|
61 | //
|
---|
62 | ///////////////////////////////////////////////////////////////////////
|
---|
63 | template<const int Radix>
|
---|
64 | struct radix_traits;
|
---|
65 |
|
---|
66 | ////////////////////////////////// Binary
|
---|
67 | template<>
|
---|
68 | struct radix_traits<2>
|
---|
69 | {
|
---|
70 | template<typename CharT>
|
---|
71 | static bool is_valid(CharT ch)
|
---|
72 | {
|
---|
73 | return ('0' == ch || '1' == ch);
|
---|
74 | }
|
---|
75 |
|
---|
76 | template<typename CharT>
|
---|
77 | static int digit(CharT ch)
|
---|
78 | {
|
---|
79 | return ch - '0';
|
---|
80 | }
|
---|
81 | };
|
---|
82 |
|
---|
83 | ////////////////////////////////// Octal
|
---|
84 | template<>
|
---|
85 | struct radix_traits<8>
|
---|
86 | {
|
---|
87 | template<typename CharT>
|
---|
88 | static bool is_valid(CharT ch)
|
---|
89 | {
|
---|
90 | return ('0' <= ch && ch <= '7');
|
---|
91 | }
|
---|
92 |
|
---|
93 | template<typename CharT>
|
---|
94 | static int digit(CharT ch)
|
---|
95 | {
|
---|
96 | return ch - '0';
|
---|
97 | }
|
---|
98 | };
|
---|
99 |
|
---|
100 | ////////////////////////////////// Decimal
|
---|
101 | template<>
|
---|
102 | struct radix_traits<10>
|
---|
103 | {
|
---|
104 | template<typename CharT>
|
---|
105 | static bool is_valid(CharT ch)
|
---|
106 | {
|
---|
107 | return impl::isdigit_(ch);
|
---|
108 | }
|
---|
109 |
|
---|
110 | template<typename CharT>
|
---|
111 | static int digit(CharT ch)
|
---|
112 | {
|
---|
113 | return ch - '0';
|
---|
114 | }
|
---|
115 | };
|
---|
116 |
|
---|
117 | ////////////////////////////////// Hexadecimal
|
---|
118 | template<>
|
---|
119 | struct radix_traits<16>
|
---|
120 | {
|
---|
121 | template<typename CharT>
|
---|
122 | static bool is_valid(CharT ch)
|
---|
123 | {
|
---|
124 | return impl::isxdigit_(ch);
|
---|
125 | }
|
---|
126 |
|
---|
127 | template<typename CharT>
|
---|
128 | static int digit(CharT ch)
|
---|
129 | {
|
---|
130 | if (impl::isdigit_(ch))
|
---|
131 | return ch - '0';
|
---|
132 | return impl::tolower_(ch) - 'a' + 10;
|
---|
133 | }
|
---|
134 | };
|
---|
135 |
|
---|
136 | ///////////////////////////////////////////////////////////////////////
|
---|
137 | //
|
---|
138 | // Helper templates for encapsulation of radix specific
|
---|
139 | // conversion of an input string to an integral value.
|
---|
140 | //
|
---|
141 | // main entry point:
|
---|
142 | //
|
---|
143 | // extract_int<Radix, MinDigits, MaxDigits, Accumulate>
|
---|
144 | // ::f(first, last, n, count);
|
---|
145 | //
|
---|
146 | // The template parameter Radix represents the radix of the
|
---|
147 | // number contained in the parsed string. The template
|
---|
148 | // parameter MinDigits specifies the minimum digits to
|
---|
149 | // accept. The template parameter MaxDigits specifies the
|
---|
150 | // maximum digits to parse. A -1 value for MaxDigits will
|
---|
151 | // make it parse an arbitrarilly large number as long as the
|
---|
152 | // numeric type can hold it. Accumulate is either
|
---|
153 | // positive_accumulate<Radix> (default) for parsing positive
|
---|
154 | // numbers or negative_accumulate<Radix> otherwise.
|
---|
155 | //
|
---|
156 | // scan.first and scan.last are iterators as usual (i.e.
|
---|
157 | // first is mutable and is moved forward when a match is
|
---|
158 | // found), n is a variable that holds the number (passed by
|
---|
159 | // reference). The number of parsed characters is added to
|
---|
160 | // count (also passed by reference)
|
---|
161 | //
|
---|
162 | // NOTE:
|
---|
163 | // Returns a non-match, if the number to parse
|
---|
164 | // overflows (or underflows) the used integral type.
|
---|
165 | // Overflow (or underflow) is detected when an
|
---|
166 | // operation wraps a value from its maximum to its
|
---|
167 | // minimum (or vice-versa). For example, overflow
|
---|
168 | // occurs when the result of the expression n * x is
|
---|
169 | // less than n (assuming n is positive and x is
|
---|
170 | // greater than 1).
|
---|
171 | //
|
---|
172 | // BEWARE:
|
---|
173 | // the parameters 'n' and 'count' should be properly
|
---|
174 | // initialized before calling this function.
|
---|
175 | //
|
---|
176 | ///////////////////////////////////////////////////////////////////////
|
---|
177 | template <int Radix>
|
---|
178 | struct positive_accumulate
|
---|
179 | {
|
---|
180 | // Use this accumulator if number is positive
|
---|
181 |
|
---|
182 | template <typename T>
|
---|
183 | static bool check(T const& n, T const& prev)
|
---|
184 | {
|
---|
185 | return n < prev;
|
---|
186 | }
|
---|
187 |
|
---|
188 | template <typename T, typename CharT>
|
---|
189 | static void add(T& n, CharT ch)
|
---|
190 | {
|
---|
191 | n += radix_traits<Radix>::digit(ch);
|
---|
192 | }
|
---|
193 | };
|
---|
194 |
|
---|
195 | template <int Radix>
|
---|
196 | struct negative_accumulate
|
---|
197 | {
|
---|
198 | // Use this accumulator if number is negative
|
---|
199 |
|
---|
200 | template <typename T>
|
---|
201 | static bool check(T const& n, T const& prev)
|
---|
202 | {
|
---|
203 | return n > prev;
|
---|
204 | }
|
---|
205 |
|
---|
206 | template <typename T, typename CharT>
|
---|
207 | static void add(T& n, CharT ch)
|
---|
208 | {
|
---|
209 | n -= radix_traits<Radix>::digit(ch);
|
---|
210 | }
|
---|
211 | };
|
---|
212 |
|
---|
213 | template <int Radix, typename Accumulate>
|
---|
214 | struct extract_int_base
|
---|
215 | {
|
---|
216 | // Common code for extract_int specializations
|
---|
217 | template <typename ScannerT, typename T>
|
---|
218 | static bool
|
---|
219 | f(ScannerT& scan, T& n)
|
---|
220 | {
|
---|
221 | T prev = n;
|
---|
222 | n *= Radix;
|
---|
223 | if (Accumulate::check(n, prev))
|
---|
224 | return false; // over/underflow!
|
---|
225 | prev = n;
|
---|
226 | Accumulate::add(n, *scan);
|
---|
227 | if (Accumulate::check(n, prev))
|
---|
228 | return false; // over/underflow!
|
---|
229 | return true;
|
---|
230 | }
|
---|
231 | };
|
---|
232 |
|
---|
233 | template <bool Bounded>
|
---|
234 | struct extract_int_
|
---|
235 | {
|
---|
236 | template <
|
---|
237 | int Radix,
|
---|
238 | unsigned MinDigits,
|
---|
239 | int MaxDigits,
|
---|
240 | typename Accumulate
|
---|
241 | >
|
---|
242 | struct apply
|
---|
243 | {
|
---|
244 | typedef extract_int_base<Radix, Accumulate> base;
|
---|
245 | typedef radix_traits<Radix> check;
|
---|
246 |
|
---|
247 | template <typename ScannerT, typename T>
|
---|
248 | static bool
|
---|
249 | f(ScannerT& scan, T& n, std::size_t& count)
|
---|
250 | {
|
---|
251 | std::size_t i = 0;
|
---|
252 | for (; (i < MaxDigits) && !scan.at_end()
|
---|
253 | && check::is_valid(*scan);
|
---|
254 | ++i, ++scan, ++count)
|
---|
255 | {
|
---|
256 | if (!base::f(scan, n))
|
---|
257 | return false; // over/underflow!
|
---|
258 | }
|
---|
259 | return i >= MinDigits;
|
---|
260 | }
|
---|
261 | };
|
---|
262 | };
|
---|
263 |
|
---|
264 | template <>
|
---|
265 | struct extract_int_<false>
|
---|
266 | {
|
---|
267 | template <
|
---|
268 | int Radix,
|
---|
269 | unsigned MinDigits,
|
---|
270 | int MaxDigits,
|
---|
271 | typename Accumulate
|
---|
272 | >
|
---|
273 | struct apply
|
---|
274 | {
|
---|
275 | typedef extract_int_base<Radix, Accumulate> base;
|
---|
276 | typedef radix_traits<Radix> check;
|
---|
277 |
|
---|
278 | template <typename ScannerT, typename T>
|
---|
279 | static bool
|
---|
280 | f(ScannerT& scan, T& n, std::size_t& count)
|
---|
281 | {
|
---|
282 | std::size_t i = 0;
|
---|
283 | for (; !scan.at_end() && check::is_valid(*scan);
|
---|
284 | ++i, ++scan, ++count)
|
---|
285 | {
|
---|
286 | if (!base::f(scan, n))
|
---|
287 | return false; // over/underflow!
|
---|
288 | }
|
---|
289 | return i >= MinDigits;
|
---|
290 | }
|
---|
291 | };
|
---|
292 | };
|
---|
293 |
|
---|
294 | //////////////////////////////////
|
---|
295 | template <
|
---|
296 | int Radix, unsigned MinDigits, int MaxDigits,
|
---|
297 | typename Accumulate = positive_accumulate<Radix>
|
---|
298 | >
|
---|
299 | struct extract_int
|
---|
300 | {
|
---|
301 | template <typename ScannerT, typename T>
|
---|
302 | static bool
|
---|
303 | f(ScannerT& scan, T& n, std::size_t& count)
|
---|
304 | {
|
---|
305 | typedef typename extract_int_<(MaxDigits >= 0)>::template
|
---|
306 | apply<Radix, MinDigits, MaxDigits, Accumulate> extractor;
|
---|
307 | return extractor::f(scan, n, count);
|
---|
308 | }
|
---|
309 | };
|
---|
310 |
|
---|
311 | ///////////////////////////////////////////////////////////////////////
|
---|
312 | //
|
---|
313 | // uint_parser_impl class
|
---|
314 | //
|
---|
315 | ///////////////////////////////////////////////////////////////////////
|
---|
316 | template <
|
---|
317 | typename T = unsigned,
|
---|
318 | int Radix = 10,
|
---|
319 | unsigned MinDigits = 1,
|
---|
320 | int MaxDigits = -1
|
---|
321 | >
|
---|
322 | struct uint_parser_impl
|
---|
323 | : parser<uint_parser_impl<T, Radix, MinDigits, MaxDigits> >
|
---|
324 | {
|
---|
325 | typedef uint_parser_impl<T, Radix, MinDigits, MaxDigits> self_t;
|
---|
326 |
|
---|
327 | template <typename ScannerT>
|
---|
328 | struct result
|
---|
329 | {
|
---|
330 | typedef typename match_result<ScannerT, T>::type type;
|
---|
331 | };
|
---|
332 |
|
---|
333 | template <typename ScannerT>
|
---|
334 | typename parser_result<self_t, ScannerT>::type
|
---|
335 | parse(ScannerT const& scan) const
|
---|
336 | {
|
---|
337 | if (!scan.at_end())
|
---|
338 | {
|
---|
339 | T n = 0;
|
---|
340 | std::size_t count = 0;
|
---|
341 | typename ScannerT::iterator_t save = scan.first;
|
---|
342 | if (extract_int<Radix, MinDigits, MaxDigits>::
|
---|
343 | f(scan, n, count))
|
---|
344 | {
|
---|
345 | return scan.create_match(count, n, save, scan.first);
|
---|
346 | }
|
---|
347 | // return no-match if number overflows
|
---|
348 | }
|
---|
349 | return scan.no_match();
|
---|
350 | }
|
---|
351 | };
|
---|
352 |
|
---|
353 | ///////////////////////////////////////////////////////////////////////
|
---|
354 | //
|
---|
355 | // int_parser_impl class
|
---|
356 | //
|
---|
357 | ///////////////////////////////////////////////////////////////////////
|
---|
358 | template <
|
---|
359 | typename T = unsigned,
|
---|
360 | int Radix = 10,
|
---|
361 | unsigned MinDigits = 1,
|
---|
362 | int MaxDigits = -1
|
---|
363 | >
|
---|
364 | struct int_parser_impl
|
---|
365 | : parser<int_parser_impl<T, Radix, MinDigits, MaxDigits> >
|
---|
366 | {
|
---|
367 | typedef int_parser_impl<T, Radix, MinDigits, MaxDigits> self_t;
|
---|
368 |
|
---|
369 | template <typename ScannerT>
|
---|
370 | struct result
|
---|
371 | {
|
---|
372 | typedef typename match_result<ScannerT, T>::type type;
|
---|
373 | };
|
---|
374 |
|
---|
375 | template <typename ScannerT>
|
---|
376 | typename parser_result<self_t, ScannerT>::type
|
---|
377 | parse(ScannerT const& scan) const
|
---|
378 | {
|
---|
379 | typedef extract_int<Radix, MinDigits, MaxDigits,
|
---|
380 | negative_accumulate<Radix> > extract_int_neg_t;
|
---|
381 | typedef extract_int<Radix, MinDigits, MaxDigits>
|
---|
382 | extract_int_pos_t;
|
---|
383 |
|
---|
384 | if (!scan.at_end())
|
---|
385 | {
|
---|
386 | T n = 0;
|
---|
387 | std::size_t count = 0;
|
---|
388 | typename ScannerT::iterator_t save = scan.first;
|
---|
389 |
|
---|
390 | bool hit = impl::extract_sign(scan, count);
|
---|
391 |
|
---|
392 | if (hit)
|
---|
393 | hit = extract_int_neg_t::f(scan, n, count);
|
---|
394 | else
|
---|
395 | hit = extract_int_pos_t::f(scan, n, count);
|
---|
396 |
|
---|
397 | if (hit)
|
---|
398 | return scan.create_match(count, n, save, scan.first);
|
---|
399 | else
|
---|
400 | scan.first = save;
|
---|
401 | // return no-match if number overflows or underflows
|
---|
402 | }
|
---|
403 | return scan.no_match();
|
---|
404 | }
|
---|
405 | };
|
---|
406 |
|
---|
407 | ///////////////////////////////////////////////////////////////////////
|
---|
408 | //
|
---|
409 | // real_parser_impl class
|
---|
410 | //
|
---|
411 | ///////////////////////////////////////////////////////////////////////
|
---|
412 | #if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310))
|
---|
413 | #pragma warning(push)
|
---|
414 | #pragma warning(disable:4127)
|
---|
415 | #endif
|
---|
416 |
|
---|
417 | template <typename RT, typename T, typename RealPoliciesT>
|
---|
418 | struct real_parser_impl
|
---|
419 | {
|
---|
420 | typedef real_parser_impl<RT, T, RealPoliciesT> self_t;
|
---|
421 |
|
---|
422 | template <typename ScannerT>
|
---|
423 | RT parse_main(ScannerT const& scan) const
|
---|
424 | {
|
---|
425 | if (scan.at_end())
|
---|
426 | return scan.no_match();
|
---|
427 | typename ScannerT::iterator_t save = scan.first;
|
---|
428 |
|
---|
429 | typedef typename parser_result<sign_parser, ScannerT>::type
|
---|
430 | sign_match_t;
|
---|
431 | typedef typename parser_result<chlit<>, ScannerT>::type
|
---|
432 | exp_match_t;
|
---|
433 |
|
---|
434 | sign_match_t sign_match = RealPoliciesT::parse_sign(scan);
|
---|
435 | std::size_t count = sign_match ? sign_match.length() : 0;
|
---|
436 | bool neg = sign_match.has_valid_attribute() ?
|
---|
437 | sign_match.value() : false;
|
---|
438 |
|
---|
439 | RT n_match = RealPoliciesT::parse_n(scan);
|
---|
440 | T n = n_match.has_valid_attribute() ?
|
---|
441 | n_match.value() : T(0);
|
---|
442 | bool got_a_number = n_match;
|
---|
443 | exp_match_t e_hit;
|
---|
444 |
|
---|
445 | if (!got_a_number && !RealPoliciesT::allow_leading_dot)
|
---|
446 | return scan.no_match();
|
---|
447 | else
|
---|
448 | count += n_match.length();
|
---|
449 |
|
---|
450 | if (neg)
|
---|
451 | n = -n;
|
---|
452 |
|
---|
453 | if (RealPoliciesT::parse_dot(scan))
|
---|
454 | {
|
---|
455 | // We got the decimal point. Now we will try to parse
|
---|
456 | // the fraction if it is there. If not, it defaults
|
---|
457 | // to zero (0) only if we already got a number.
|
---|
458 |
|
---|
459 | if (RT hit = RealPoliciesT::parse_frac_n(scan))
|
---|
460 | {
|
---|
461 | hit.value(hit.value()
|
---|
462 | * BOOST_SPIRIT_IMPL_STD_NS::
|
---|
463 | pow(T(10), T(-hit.length())));
|
---|
464 | if (neg)
|
---|
465 | n -= hit.value();
|
---|
466 | else
|
---|
467 | n += hit.value();
|
---|
468 | count += hit.length() + 1;
|
---|
469 |
|
---|
470 | }
|
---|
471 |
|
---|
472 | else if (!got_a_number ||
|
---|
473 | !RealPoliciesT::allow_trailing_dot)
|
---|
474 | return scan.no_match();
|
---|
475 |
|
---|
476 | e_hit = RealPoliciesT::parse_exp(scan);
|
---|
477 | }
|
---|
478 | else
|
---|
479 | {
|
---|
480 | // We have reached a point where we
|
---|
481 | // still haven't seen a number at all.
|
---|
482 | // We return early with a no-match.
|
---|
483 | if (!got_a_number)
|
---|
484 | return scan.no_match();
|
---|
485 |
|
---|
486 | // If we must expect a dot and we didn't see
|
---|
487 | // an exponent, return early with a no-match.
|
---|
488 | e_hit = RealPoliciesT::parse_exp(scan);
|
---|
489 | if (RealPoliciesT::expect_dot && !e_hit)
|
---|
490 | return scan.no_match();
|
---|
491 | }
|
---|
492 |
|
---|
493 | if (e_hit)
|
---|
494 | {
|
---|
495 | // We got the exponent prefix. Now we will try to parse the
|
---|
496 | // actual exponent. It is an error if it is not there.
|
---|
497 | if (RT e_n_hit = RealPoliciesT::parse_exp_n(scan))
|
---|
498 | {
|
---|
499 | n *= BOOST_SPIRIT_IMPL_STD_NS::
|
---|
500 | pow(T(10), T(e_n_hit.value()));
|
---|
501 | count += e_n_hit.length() + e_hit.length();
|
---|
502 | }
|
---|
503 | else
|
---|
504 | {
|
---|
505 | // Oops, no exponent, return a no-match
|
---|
506 | return scan.no_match();
|
---|
507 | }
|
---|
508 | }
|
---|
509 |
|
---|
510 | return scan.create_match(count, n, save, scan.first);
|
---|
511 | }
|
---|
512 |
|
---|
513 | template <typename ScannerT>
|
---|
514 | static RT parse(ScannerT const& scan)
|
---|
515 | {
|
---|
516 | static self_t this_;
|
---|
517 | return impl::implicit_lexeme_parse<RT>(this_, scan, scan);
|
---|
518 | }
|
---|
519 | };
|
---|
520 |
|
---|
521 | #if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310))
|
---|
522 | #pragma warning(pop)
|
---|
523 | #pragma warning(disable:4127)
|
---|
524 | #endif
|
---|
525 |
|
---|
526 | } // namespace impl
|
---|
527 |
|
---|
528 | ///////////////////////////////////////////////////////////////////////////////
|
---|
529 | }} // namespace boost::spirit
|
---|
530 |
|
---|
531 | #endif
|
---|
532 | #undef BOOST_SPIRIT_IMPL_STD_NS
|
---|