source: NonGTP/Boost/boost/spirit/core/primitives/impl/numerics.ipp @ 857

Revision 857, 18.5 KB checked in by igarcia, 19 years ago (diff)
Line 
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
21namespace 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
Note: See TracBrowser for help on using the repository browser.