From be33d016e91c042725583f03d23bda65fa10c216 Mon Sep 17 00:00:00 2001 From: Doug Currie Date: Fri, 8 Jan 2016 15:55:00 -0500 Subject: [PATCH] Refactor read_unsigned to prepare for pluggable atod --- .gitignore | 1 + extlib/benz/include/picrin/compat.h | 63 +++++++++++++ extlib/benz/read.c | 136 +++++++++------------------- 3 files changed, 109 insertions(+), 91 deletions(-) diff --git a/.gitignore b/.gitignore index c799dc45..d31d791a 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ GTAGS _build _static _template +.DS_Store diff --git a/extlib/benz/include/picrin/compat.h b/extlib/benz/include/picrin/compat.h index 30af63b9..4794b717 100644 --- a/extlib/benz/include/picrin/compat.h +++ b/extlib/benz/include/picrin/compat.h @@ -213,6 +213,69 @@ strcpy(char *dst, const char *src) return d; } +PIC_INLINE double +atof(const char *nptr) +{ + int c; + double f, g, h; + int exp, s, i, e; + unsigned u; + + /* note that picrin_read always assures that *nptr is a digit, never a '+' or '-' */ + /* in other words, the result of atof will always be positive */ + + /* mantissa */ + /* pre '.' */ + u = *nptr++ - '0'; + while (isdigit(c = *nptr)) { + u = u * 10 + (*nptr++ - '0'); + } + if (c == '.') { + /* after '.' */ + g = 0, e = 0; + while (isdigit(c = *nptr)) { + g = g * 10 + (*nptr++ - '0'); + e++; + } + h = 1.0; + while (e-- > 0) { + h /= 10; + } + f = u + g * h; + } + else { + f = u; + } + /* suffix, i.e., exponent */ + s = 0; + exp = 0; + c = *nptr; + + if (c == 'e' && c == 'E') { + nptr++; + switch ((c = *nptr++)) { + case '-': + s = 1; + case '+': + c = *nptr++; + default: + exp = c - '0'; + while (isdigit(c = *nptr)) { + exp = exp * 10 + (*nptr++ - '0'); + } + } + } + e = 10; + for (i = 0; exp; ++i) { + if ((exp & 1) != 0) { + f = s ? f / e : (f * e); + } + e *= e; + exp >>= 1; + } + return f; +} + #endif #if PIC_ENABLE_STDIO diff --git a/extlib/benz/read.c b/extlib/benz/read.c index 618317c9..5299e540 100644 --- a/extlib/benz/read.c +++ b/extlib/benz/read.c @@ -237,104 +237,58 @@ read_uinteger(pic_state *pic, struct pic_port *port, int c) return u; } -static int -read_suffix(pic_state *pic, struct pic_port *port) -{ - int c, s = 1; - - c = peek(pic, port); - - if (c != 'e' && c != 'E') { - return 0; - } - - next(pic, port); - - switch ((c = next(pic, port))) { - case '-': - s = -1; - case '+': - c = next(pic, port); - default: - return s * read_uinteger(pic, port, c); - } -} - static pic_value read_unsigned(pic_state *pic, struct pic_port *port, int c) { - unsigned u; - int exp, s, i, e; +#define ATOF_BUF_SIZE (64) + char buf[ATOF_BUF_SIZE]; + double flt; + int idx = 0; /* index into buffer */ + int dpe = 0; /* the number of '.' or 'e' characters seen */ - u = read_uinteger(pic, port, c); - - switch (peek(pic, port)) { -#if PIC_ENABLE_LIBC - case '.': { - char buf[256]; - i = sprintf(buf, "%d", u); - buf[i++] = next(pic, port); - while (isdigit(c = peek(pic, port))) { - buf[i++] = next(pic, port); - } - sprintf(buf + i, "e%d", read_suffix(pic, port)); - return pic_float_value(atof(buf)); + if (! isdigit(c)) { + read_error(pic, "expected one or more digits", pic_list1(pic, pic_char_value(c))); } -#else - case '.': { - double f, g, h; - next(pic, port); - g = 0, e = 0; - while (isdigit(c = peek(pic, port))) { - g = g * 10 + (next(pic, port) - '0'); - e++; - } - h = 1.0; - while (e-- > 0) { - h /= 10; - } - f = u + g * h; - - exp = read_suffix(pic, port); - if (exp >= 0) { - s = 0; - } else { - exp = -exp; - s = 1; - } - - e = 10; - for (i = 0; exp; ++i) { - if ((exp & 1) != 0) { - f = s ? f / e : (f * e); - } - e *= e; - exp >>= 1; - } - return pic_float_value(f); + buf[idx++] = (char )c; + while (isdigit(c = peek(pic, port)) && idx < ATOF_BUF_SIZE) { + buf[idx++] = (char )next(pic, port); } -#endif - - default: - exp = read_suffix(pic, port); - if (exp >= 0) { - s = 0; - } else { - exp = -exp; - s = 1; + if ('.' == peek(pic, port) && idx < ATOF_BUF_SIZE) { + dpe++; + buf[idx++] = (char )next(pic, port); + while (isdigit(c = peek(pic, port)) && idx < ATOF_BUF_SIZE) { + buf[idx++] = (char )next(pic, port); } - - e = 10; - for (i = 0; exp; ++i) { - if ((exp & 1) != 0) { - u = s ? u / e : (u * e); - } - e *= e; - exp >>= 1; - } - - return pic_int_value(u); } + c = peek(pic, port); + + if ((c == 'e' || c == 'E') && idx < (ATOF_BUF_SIZE - 2)) { + dpe++; + buf[idx++] = (char )next(pic, port); + switch ((c = peek(pic, port))) { + case '-': + case '+': + buf[idx++] = (char )next(pic, port); + break; + default: + break; + } + if (! isdigit(peek(pic, port))) { + read_error(pic, "expected one or more digits", pic_list1(pic, pic_char_value(c))); + } + while (isdigit(c = peek(pic, port)) && idx < ATOF_BUF_SIZE) { + buf[idx++] = (char )next(pic, port); + } + } + if (idx >= ATOF_BUF_SIZE) + read_error(pic, "number too large", + pic_obj_value(pic_make_str(pic, (const char *)buf, ATOF_BUF_SIZE))); + buf[idx] = 0; + flt = atof(buf); + + if (dpe == 0 && pic_valid_int(flt)) + return pic_int_value((int )flt); + return pic_float_value(flt); } static pic_value @@ -346,7 +300,7 @@ read_number(pic_state *pic, struct pic_port *port, int c) static pic_value negate(pic_value n) { - if (pic_int_p(n)) { + if (pic_int_p(n) && (INT_MIN != pic_int(n))) { return pic_int_value(-pic_int(n)); } else { return pic_float_value(-pic_float(n));