diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/codegen.c | 60 |
1 files changed, 51 insertions, 9 deletions
diff --git a/src/codegen.c b/src/codegen.c index 5803a9c25..1f6d16477 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -959,6 +959,48 @@ readint_float(codegen_scope *s, const char *p, int base) return f; } +static mrb_int +readint_mrb_int(codegen_scope *s, const char *p, int base, int neg, int *overflow) +{ + const char *e = p + strlen(p); + mrb_int result = 0; + int n; + + if (*p == '+') p++; + while (p < e) { + char c = *p; + c = tolower((unsigned char)c); + for (n=0; n<base; n++) { + if (mrb_digitmap[n] == c) { + break; + } + } + if (n == base) { + codegen_error(s, "malformed readint input"); + } + + if (neg) { + if ((MRB_INT_MIN + n)/base > result) { + *overflow = TRUE; + return 0; + } + result *= base; + result -= n; + } + else { + if ((MRB_INT_MAX - n)/base < result) { + *overflow = TRUE; + return 0; + } + result *= base; + result += n; + } + p++; + } + *overflow = FALSE; + return result; +} + static void codegen(codegen_scope *s, node *tree, int val) { @@ -1733,18 +1775,18 @@ codegen(codegen_scope *s, node *tree, int val) if (val) { char *p = (char*)tree->car; int base = (intptr_t)tree->cdr->car; - double f; mrb_int i; mrb_code co; + int overflow; - f = readint_float(s, p, base); - if (!FIXABLE(f)) { + i = readint_mrb_int(s, p, base, FALSE, &overflow); + if (overflow) { + double f = readint_float(s, p, base); int off = new_lit(s, mrb_float_value(f)); genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); } else { - i = (mrb_int)f; if (i < MAXARG_sBx && i > -MAXARG_sBx) { co = MKOP_AsBx(OP_LOADI, cursp(), i); } @@ -1789,18 +1831,18 @@ codegen(codegen_scope *s, node *tree, int val) { char *p = (char*)tree->car; int base = (intptr_t)tree->cdr->car; - mrb_float f; mrb_int i; mrb_code co; + int overflow; - f = readint_float(s, p, base); - if (!FIXABLE(f)) { + i = readint_mrb_int(s, p, base, TRUE, &overflow); + if (overflow) { + double f = readint_float(s, p, base); int off = new_lit(s, mrb_float_value(-f)); - + genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); } else { - i = (mrb_int)-f; if (i < MAXARG_sBx && i > -MAXARG_sBx) { co = MKOP_AsBx(OP_LOADI, cursp(), i); } |
