Numworks Epsilon  1.4.1
Graphing Calculator Operating System
parsenum.c
Go to the documentation of this file.
1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2013, 2014 Damien P. George
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  */
26 
27 #include <stdbool.h>
28 #include <stdlib.h>
29 
30 #include "py/runtime.h"
31 #include "py/parsenumbase.h"
32 #include "py/parsenum.h"
33 #include "py/smallint.h"
34 
35 #if MICROPY_PY_BUILTINS_FLOAT
36 #include <math.h>
37 #endif
38 
40  // if lex!=NULL then the parser called us and we need to convert the
41  // exception's type from ValueError to SyntaxError and add traceback info
42  if (lex != NULL) {
44  mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTR_NULL);
45  }
46  nlr_raise(exc);
47 }
48 
49 mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, mp_lexer_t *lex) {
50  const byte *restrict str = (const byte *)str_;
51  const byte *restrict top = str + len;
52  bool neg = false;
53  mp_obj_t ret_val;
54 
55  // check radix base
56  if ((base != 0 && base < 2) || base > 36) {
57  // this won't be reached if lex!=NULL
58  mp_raise_ValueError("int() arg 2 must be >= 2 and <= 36");
59  }
60 
61  // skip leading space
62  for (; str < top && unichar_isspace(*str); str++) {
63  }
64 
65  // parse optional sign
66  if (str < top) {
67  if (*str == '+') {
68  str++;
69  } else if (*str == '-') {
70  str++;
71  neg = true;
72  }
73  }
74 
75  // parse optional base prefix
76  str += mp_parse_num_base((const char*)str, top - str, &base);
77 
78  // string should be an integer number
79  mp_int_t int_val = 0;
80  const byte *restrict str_val_start = str;
81  for (; str < top; str++) {
82  // get next digit as a value
83  mp_uint_t dig = *str;
84  if ('0' <= dig && dig <= '9') {
85  dig -= '0';
86  } else {
87  dig |= 0x20; // make digit lower-case
88  if ('a' <= dig && dig <= 'z') {
89  dig -= 'a' - 10;
90  } else {
91  // unknown character
92  break;
93  }
94  }
95  if (dig >= (mp_uint_t)base) {
96  break;
97  }
98 
99  // add next digi and check for overflow
100  if (mp_small_int_mul_overflow(int_val, base)) {
101  goto overflow;
102  }
103  int_val = int_val * base + dig;
104  if (!MP_SMALL_INT_FITS(int_val)) {
105  goto overflow;
106  }
107  }
108 
109  // negate value if needed
110  if (neg) {
111  int_val = -int_val;
112  }
113 
114  // create the small int
115  ret_val = MP_OBJ_NEW_SMALL_INT(int_val);
116 
117 have_ret_val:
118  // check we parsed something
119  if (str == str_val_start) {
120  goto value_error;
121  }
122 
123  // skip trailing space
124  for (; str < top && unichar_isspace(*str); str++) {
125  }
126 
127  // check we reached the end of the string
128  if (str != top) {
129  goto value_error;
130  }
131 
132  // return the object
133  return ret_val;
134 
135 overflow:
136  // reparse using long int
137  {
138  const char *s2 = (const char*)str_val_start;
139  ret_val = mp_obj_new_int_from_str_len(&s2, top - str_val_start, neg, base);
140  str = (const byte*)s2;
141  goto have_ret_val;
142  }
143 
144 value_error:
147  "invalid syntax for integer");
148  raise_exc(exc, lex);
151  "invalid syntax for integer with base %d", base);
152  raise_exc(exc, lex);
153  } else {
154  vstr_t vstr;
155  mp_print_t print;
156  vstr_init_print(&vstr, 50, &print);
157  mp_printf(&print, "invalid syntax for integer with base %d: ", base);
158  mp_str_print_quoted(&print, str_val_start, top - str_val_start, true);
161  raise_exc(exc, lex);
162  }
163 }
164 
165 typedef enum {
170 
171 mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool force_complex, mp_lexer_t *lex) {
172 #if MICROPY_PY_BUILTINS_FLOAT
173  const char *top = str + len;
174  mp_float_t dec_val = 0;
175  bool dec_neg = false;
176  bool imag = false;
177 
178  // skip leading space
179  for (; str < top && unichar_isspace(*str); str++) {
180  }
181 
182  // parse optional sign
183  if (str < top) {
184  if (*str == '+') {
185  str++;
186  } else if (*str == '-') {
187  str++;
188  dec_neg = true;
189  }
190  }
191 
192  const char *str_val_start = str;
193 
194  // determine what the string is
195  if (str < top && (str[0] | 0x20) == 'i') {
196  // string starts with 'i', should be 'inf' or 'infinity' (case insensitive)
197  if (str + 2 < top && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'f') {
198  // inf
199  str += 3;
200  dec_val = INFINITY;
201  if (str + 4 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'i' && (str[3] | 0x20) == 't' && (str[4] | 0x20) == 'y') {
202  // infinity
203  str += 5;
204  }
205  }
206  } else if (str < top && (str[0] | 0x20) == 'n') {
207  // string starts with 'n', should be 'nan' (case insensitive)
208  if (str + 2 < top && (str[1] | 0x20) == 'a' && (str[2] | 0x20) == 'n') {
209  // NaN
210  str += 3;
211  dec_val = MICROPY_FLOAT_C_FUN(nan)("");
212  }
213  } else {
214  // string should be a decimal number
216  bool exp_neg = false;
217  mp_float_t frac_mult = 0.1;
218  mp_int_t exp_val = 0;
219  while (str < top) {
220  mp_uint_t dig = *str++;
221  if ('0' <= dig && dig <= '9') {
222  dig -= '0';
223  if (in == PARSE_DEC_IN_EXP) {
224  exp_val = 10 * exp_val + dig;
225  } else {
226  if (in == PARSE_DEC_IN_FRAC) {
227  dec_val += dig * frac_mult;
228  frac_mult *= MICROPY_FLOAT_CONST(0.1);
229  } else {
230  dec_val = 10 * dec_val + dig;
231  }
232  }
233  } else if (in == PARSE_DEC_IN_INTG && dig == '.') {
234  in = PARSE_DEC_IN_FRAC;
235  } else if (in != PARSE_DEC_IN_EXP && ((dig | 0x20) == 'e')) {
236  in = PARSE_DEC_IN_EXP;
237  if (str < top) {
238  if (str[0] == '+') {
239  str++;
240  } else if (str[0] == '-') {
241  str++;
242  exp_neg = true;
243  }
244  }
245  if (str == top) {
246  goto value_error;
247  }
248  } else if (allow_imag && (dig | 0x20) == 'j') {
249  imag = true;
250  break;
251  } else {
252  // unknown character
253  str--;
254  break;
255  }
256  }
257 
258  // work out the exponent
259  if (exp_neg) {
260  exp_val = -exp_val;
261  }
262 
263  // apply the exponent
264  dec_val *= MICROPY_FLOAT_C_FUN(pow)(10, exp_val);
265  }
266 
267  // negate value if needed
268  if (dec_neg) {
269  dec_val = -dec_val;
270  }
271 
272  // check we parsed something
273  if (str == str_val_start) {
274  goto value_error;
275  }
276 
277  // skip trailing space
278  for (; str < top && unichar_isspace(*str); str++) {
279  }
280 
281  // check we reached the end of the string
282  if (str != top) {
283  goto value_error;
284  }
285 
286  // return the object
287 #if MICROPY_PY_BUILTINS_COMPLEX
288  if (imag) {
289  return mp_obj_new_complex(0, dec_val);
290  } else if (force_complex) {
291  return mp_obj_new_complex(dec_val, 0);
292 #else
293  if (imag || force_complex) {
294  raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "complex values not supported"), lex);
295 #endif
296  } else {
297  return mp_obj_new_float(dec_val);
298  }
299 
300 value_error:
301  raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid syntax for number"), lex);
302 
303 #else
304  raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "decimal numbers not supported"), lex);
305 #endif
306 }
intptr_t mp_int_t
Definition: mpconfigport.h:73
uintptr_t mp_uint_t
Definition: mpconfigport.h:74
Definition: misc.h:142
#define MICROPY_ERROR_REPORTING_TERSE
Definition: mpconfig.h:521
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt,...)
Definition: objexcept.c:380
void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes)
Definition: objstr.c:45
bool mp_small_int_mul_overflow(mp_int_t x, mp_int_t y)
Definition: smallint.c:29
#define STATIC
Definition: mpconfig.h:1178
const mp_obj_type_t mp_type_SyntaxError
STATIC NORETURN void raise_exc(mp_obj_t exc, mp_lexer_t *lex)
Definition: parsenum.c:39
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg)
Definition: objexcept.c:343
size_t tok_line
Definition: lexer.h:164
#define MP_OBJ_NEW_SMALL_INT(small_int)
Definition: obj.h:87
#define MICROPY_ERROR_REPORTING
Definition: mpconfigport.h:32
bool unichar_isspace(unichar c)
Definition: unicode.c:128
#define MICROPY_ERROR_REPORTING_NORMAL
Definition: mpconfig.h:523
#define NULL
Definition: stddef.h:4
mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg)
Definition: objexcept.c:334
#define MP_SMALL_INT_FITS(n)
Definition: smallint.h:40
#define pow(x, y)
Definition: math.h:190
const mp_obj_type_t mp_type_str
Definition: objstr.c:1950
const mp_obj_type_t mp_type_ValueError
mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base)
Definition: objint.c:326
#define NORETURN
Definition: mpconfig.h:1268
void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qstr block)
Definition: objexcept.c:485
unsigned char byte
Definition: misc.h:37
mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr)
Definition: objstr.c:1998
#define INFINITY
Definition: math.h:29
mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool force_complex, mp_lexer_t *lex)
Definition: parsenum.c:171
NORETURN void mp_raise_ValueError(const char *msg)
Definition: runtime.c:1456
#define MP_OBJ_TO_PTR(o)
Definition: obj.h:228
#define nlr_raise(val)
Definition: nlr.h:89
mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, mp_lexer_t *lex)
Definition: parsenum.c:49
uint64_t mp_obj_t
Definition: obj.h:39
parse_dec_in_t
Definition: parsenum.c:165
int mp_printf(const mp_print_t *print, const char *fmt,...)
Definition: mpprint.c:380
qstr source_name
Definition: lexer.h:149
void vstr_init_print(vstr_t *vstr, size_t alloc, struct _mp_print_t *print)
Definition: vstr.c:64
size_t mp_parse_num_base(const char *str, size_t len, int *base)
Definition: parsenumbase.c:33
#define nan(s)
Definition: math.h:189