diff options
author | Damien George <damien.p.george@gmail.com> | 2014-02-22 18:12:43 +0000 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2014-02-22 18:12:43 +0000 |
commit | 20773971186151b53426bd607908546598036a16 (patch) | |
tree | c74ee3ac2f07061a820355bac0bea075e0177fa8 /py/parsenum.c | |
parent | 2613ffde431594f3fe0562042c32105623fbe4dc (diff) |
py: Put number parsing code together in parsenum.c.
Diffstat (limited to 'py/parsenum.c')
-rw-r--r-- | py/parsenum.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/py/parsenum.c b/py/parsenum.c new file mode 100644 index 000000000..64594cd1b --- /dev/null +++ b/py/parsenum.c @@ -0,0 +1,169 @@ +#include <stdlib.h> + +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "nlr.h" +#include "obj.h" +#include "parsenum.h" + +#if defined(UNIX) + +#include <ctype.h> +#include <errno.h> + +mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) { + // TODO at the moment we ignore len; we should honour it! + // TODO detect integer overflow and return bignum + + int c, neg = 0; + const char *p = str; + char *num; + long found; + + // check radix base + if ((base != 0 && base < 2) || base > 36) { + nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "ValueError: int() arg 2 must be >=2 and <= 36")); + } + // skip surrounded whitespace + while (isspace((c = *(p++)))); + if (c == 0) { + goto value_error; + } + // preced sign + if (c == '+' || c == '-') { + neg = - (c == '-'); + c = *(p++); + } + + // find real radix base, and strip preced '0x', '0o' and '0b' + // TODO somehow merge with similar code in parse.c + if ((base == 0 || base == 16) && c == '0') { + c = *(p++); + if ((c | 32) == 'x') { + base = 16; + } else if (base == 0 && (c | 32) == 'o') { + base = 8; + } else if (base == 0 && (c | 32) == 'b') { + base = 2; + } else { + base = 10; + p -= 2; + } + } else if (base == 8 && c == '0') { + c = *(p++); + if ((c | 32) != 'o') { + p -= 2; + } + } else if (base == 2 && c == '0') { + c = *(p++); + if ((c | 32) != 'b') { + p -= 2; + } + } else { + if (base == 0) base = 10; + p--; + } + + errno = 0; + found = strtol(p, &num, base); + if (errno) { + goto value_error; + } else if (found && *(num) == 0) { + goto done; + } else if (found || num != p) { + goto check_tail_space; + } else { + goto value_error; + } + +check_tail_space: + if (*(num) != 0) { + while (isspace((c = *(num++)))); + if (c != 0) { + goto value_error; + } + } + +done: + return MP_OBJ_NEW_SMALL_INT((found ^ neg) - neg); + +value_error: + nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid literal for int() with base %d: '%s'", base, str)); +} + +#else /* defined(UNIX) */ + +mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) { + // TODO port strtol to stm + return MP_OBJ_NEW_SMALL_INT(0); +} + +#endif /* defined(UNIX) */ + +#define PARSE_DEC_IN_INTG (1) +#define PARSE_DEC_IN_FRAC (2) +#define PARSE_DEC_IN_EXP (3) + +mp_obj_t mp_parse_num_decimal(const char *str, uint len) { +#if MICROPY_ENABLE_FLOAT + int in = PARSE_DEC_IN_INTG; + mp_float_t dec_val = 0; + bool exp_neg = false; + int exp_val = 0; + int exp_extra = 0; + bool imag = false; + const char *top = str + len; + for (; str < top; str++) { + int dig = *str; + if ('0' <= dig && dig <= '9') { + dig -= '0'; + if (in == PARSE_DEC_IN_EXP) { + exp_val = 10 * exp_val + dig; + } else { + dec_val = 10 * dec_val + dig; + if (in == PARSE_DEC_IN_FRAC) { + exp_extra -= 1; + } + } + } else if (in == PARSE_DEC_IN_INTG && dig == '.') { + in = PARSE_DEC_IN_FRAC; + } else if (in != PARSE_DEC_IN_EXP && (dig == 'E' || dig == 'e')) { + in = PARSE_DEC_IN_EXP; + if (str[1] == '+') { + str++; + } else if (str[1] == '-') { + str++; + exp_neg = true; + } + } else if (dig == 'J' || dig == 'j') { + str++; + imag = true; + break; + } else { + // unknown character + break; + } + } + if (*str != 0) { + nlr_jump(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number")); + } + if (exp_neg) { + exp_val = -exp_val; + } + exp_val += exp_extra; + for (; exp_val > 0; exp_val--) { + dec_val *= 10; + } + for (; exp_val < 0; exp_val++) { + dec_val *= 0.1; + } + if (imag) { + return mp_obj_new_complex(0, dec_val); + } else { + return mp_obj_new_float(dec_val); + } +#else + nlr_jump(mp_obj_new_exception_msg(&mp_type_SyntaxError, "decimal numbers not supported")); +#endif +} |