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