From 5ce271e9fed1142fc0a9b459ec3ed31ddbe8e0c1 Mon Sep 17 00:00:00 2001 From: Yuichi Nishiwaki Date: Thu, 3 Mar 2016 19:42:18 +0900 Subject: [PATCH] simplify number reader --- extlib/benz/number.c | 84 ++++++++++++++++++----- extlib/benz/read.c | 158 +++++++------------------------------------ 2 files changed, 91 insertions(+), 151 deletions(-) diff --git a/extlib/benz/number.c b/extlib/benz/number.c index eae2f41d..2c22ead0 100644 --- a/extlib/benz/number.c +++ b/extlib/benz/number.c @@ -248,6 +248,62 @@ pic_number_number_to_string(pic_state *pic) return str; } +static bool +strcaseeq(const char *s1, const char *s2) +{ + char a, b; + + while ((a = *s1++) * (b = *s2++)) { + if (tolower(a) != tolower(b)) + return false; + } + return a == b; +} + +static pic_value +string_to_number(pic_state *pic, const char *str) +{ + double flt; + const char *c = str; + bool isint = 1; + + if (*c == '+' || *c == '-') + c++; + + if (! isdigit(*c++)) { + return pic_false_value(pic); + } + while (isdigit(*c)) c++; + + if (*c == '.') { + isint = false; + c++; + while (isdigit(*c)) c++; + } + if (*c == 'e' || *c == 'E') { + isint = false; + c++; + if (*c == '+' || *c == '-') + c++; + if (! isdigit(*c++)) { + return pic_false_value(pic); + } + while (isdigit(*c)) c++; + } + + if (*c != '\0') { + return pic_false_value(pic); + } + + flt = PIC_CSTRING_TO_DOUBLE(str); + + if (isint && INT_MIN <= flt && flt <= INT_MAX) { + return pic_int_value(pic, flt); + } else { + return pic_float_value(pic, flt); + } +} + static pic_value pic_number_string_to_number(pic_state *pic) { @@ -255,30 +311,24 @@ pic_number_string_to_number(pic_state *pic) int radix = 10; long num; char *eptr; - pic_value flo = pic_false_value(pic), e; pic_get_args(pic, "z|i", &str, &radix); + if (strcaseeq(str, "+inf.0")) + return pic_float_value(pic, 1.0 / 0.0); + if (strcaseeq(str, "-inf.0")) + return pic_float_value(pic, -1.0 / 0.0); + if (strcaseeq(str, "+nan.0")) + return pic_float_value(pic, 0.0 / 0.0); + if (strcaseeq(str, "-nan.0")) + return pic_float_value(pic, -0.0 / 0.0); + num = strtol(str, &eptr, radix); if (*eptr == '\0') { - return INT_MIN <= num && num <= INT_MAX - ? pic_int_value(pic, num) - : pic_float_value(pic, num); + return INT_MIN <= num && num <= INT_MAX ? pic_int_value(pic, num) : pic_float_value(pic, num); } - pic_try { - flo = pic_read_cstr(pic, str); - } - pic_catch(e) { - /* swallow error */ - (void)e; - } - - if (pic_int_p(pic, flo) || pic_float_p(pic, flo)) { - return flo; - } - - return pic_false_value(pic); + return string_to_number(pic, str); } void diff --git a/extlib/benz/read.c b/extlib/benz/read.c index 3b4f3262..6540fe3f 100644 --- a/extlib/benz/read.c +++ b/extlib/benz/read.c @@ -79,18 +79,6 @@ isdelim(int c) return c == EOF || strchr("();,|\" \t\n\r", c) != NULL; /* ignores "#", "'" */ } -static bool -strcaseeq(const char *s1, const char *s2) -{ - char a, b; - - while ((a = *s1++) * (b = *s2++)) { - if (tolower(a) != tolower(b)) - return false; - } - return a == b; -} - static int case_fold(int c, struct reader_control *p) { @@ -214,11 +202,10 @@ read_syntax_unquote(pic_state *pic, xFILE *file, int PIC_UNUSED(c), struct reade } static pic_value -read_symbol(pic_state *pic, xFILE *file, int c, struct reader_control *p) -{ +read_atom(pic_state *pic, xFILE *file, int c, struct reader_control *p) { int len; char *buf; - pic_value sym; + pic_value str; len = 1; buf = pic_malloc(pic, len + 1); @@ -233,10 +220,28 @@ read_symbol(pic_state *pic, xFILE *file, int c, struct reader_control *p) buf[len] = 0; } - sym = pic_intern_cstr(pic, buf); + str = pic_str_value(pic, buf, len); pic_free(pic, buf); - return sym; + return str; +} + +static pic_value +read_symbol(pic_state *pic, xFILE *file, int c, struct reader_control *p) +{ + return pic_intern(pic, read_atom(pic, file, c, p)); +} + +static pic_value +read_number(pic_state *pic, xFILE *file, int c, struct reader_control *p) +{ + pic_value str = read_atom(pic, file, c, p), num; + + num = pic_funcall(pic, "picrin.base", "string->number", 1, str); + if (! pic_false_p(pic, num)) { + return num; + } + return pic_intern(pic, str); } static unsigned @@ -256,119 +261,6 @@ read_uinteger(pic_state *pic, xFILE *file, int c, struct reader_control *PIC_UNU return u; } -static pic_value -read_unsigned(pic_state *pic, xFILE *file, int c, struct reader_control *PIC_UNUSED(p)) -{ -#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 */ - - if (! isdigit(c)) { - read_error(pic, "expected one or more digits", pic_list(pic, 1, pic_char_value(pic, c))); - } - buf[idx++] = (char )c; - while (isdigit(c = peek(pic, file)) && idx < ATOF_BUF_SIZE) { - buf[idx++] = (char )next(pic, file); - } - if ('.' == peek(pic, file) && idx < ATOF_BUF_SIZE) { - dpe++; - buf[idx++] = (char )next(pic, file); - while (isdigit(c = peek(pic, file)) && idx < ATOF_BUF_SIZE) { - buf[idx++] = (char )next(pic, file); - } - } - c = peek(pic, file); - - if ((c == 'e' || c == 'E') && idx < (ATOF_BUF_SIZE - 2)) { - dpe++; - buf[idx++] = (char )next(pic, file); - switch ((c = peek(pic, file))) { - case '-': - case '+': - buf[idx++] = (char )next(pic, file); - break; - default: - break; - } - if (! isdigit(peek(pic, file))) { - read_error(pic, "expected one or more digits", pic_list(pic, 1, pic_char_value(pic, c))); - } - while (isdigit(c = peek(pic, file)) && idx < ATOF_BUF_SIZE) { - buf[idx++] = (char )next(pic, file); - } - } - if (idx >= ATOF_BUF_SIZE) - read_error(pic, "number too large", pic_list(pic, 1, pic_str_value(pic, (const char *)buf, ATOF_BUF_SIZE))); - - if (! isdelim(c)) - read_error(pic, "non-delimiter character given after number", pic_list(pic, 1, pic_char_value(pic, c))); - - buf[idx] = 0; - flt = PIC_CSTRING_TO_DOUBLE(buf); - - if (dpe == 0 && INT_MIN <= flt && flt <= INT_MAX) - return pic_int_value(pic, flt); - return pic_float_value(pic, flt); -} - -static pic_value -read_number(pic_state *pic, xFILE *file, int c, struct reader_control *p) -{ - return read_unsigned(pic, file, c, p); -} - -static pic_value -negate(pic_state *pic, pic_value n) -{ - if (pic_int_p(pic, n) && (INT_MIN != pic_int(pic, n))) { - return pic_int_value(pic, -pic_int(pic, n)); - } else { - return pic_float_value(pic, -pic_float(pic, n)); - } -} - -static pic_value -read_minus(pic_state *pic, xFILE *file, int c, struct reader_control *p) -{ - pic_value sym; - - if (isdigit(peek(pic, file))) { - return negate(pic, read_unsigned(pic, file, next(pic, file), p)); - } - else { - sym = read_symbol(pic, file, c, p); - if (strcaseeq(pic_sym(pic, sym), "-inf.0")) { - return pic_float_value(pic, -(1.0 / 0.0)); - } - if (strcaseeq(pic_sym(pic, sym), "-nan.0")) { - return pic_float_value(pic, -(0.0 / 0.0)); - } - return sym; - } -} - -static pic_value -read_plus(pic_state *pic, xFILE *file, int c, struct reader_control *p) -{ - pic_value sym; - - if (isdigit(peek(pic, file))) { - return read_unsigned(pic, file, next(pic, file), p); - } - else { - sym = read_symbol(pic, file, c, p); - if (strcaseeq(pic_sym(pic, sym), "+inf.0")) { - return pic_float_value(pic, 1.0 / 0.0); - } - if (strcaseeq(pic_sym(pic, sym), "+nan.0")) { - return pic_float_value(pic, 0.0 / 0.0); - } - return sym; - } -} - static pic_value read_true(pic_state *pic, xFILE *file, int c, struct reader_control *PIC_UNUSED(p)) { @@ -787,12 +679,10 @@ reader_table_init(void) reader_table[','] = read_unquote; reader_table['"'] = read_string; reader_table['|'] = read_pipe; - reader_table['+'] = read_plus; - reader_table['-'] = read_minus; reader_table['('] = read_pair; reader_table['#'] = read_dispatch; - - /* read number */ + reader_table['+'] = read_number; + reader_table['-'] = read_number; for (c = '0'; c <= '9'; ++c) { reader_table[c] = read_number; }