Skip to content
This repository has been archived by the owner on Mar 26, 2024. It is now read-only.

Commit

Permalink
simplify number reader
Browse files Browse the repository at this point in the history
  • Loading branch information
nyuichi committed Mar 3, 2016
1 parent 85b58bd commit 5ce271e
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 150 deletions.
84 changes: 67 additions & 17 deletions extlib/benz/number.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,37 +248,87 @@ 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)
{
const char *str;
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);
}

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 INT_MIN <= num && num <= INT_MAX ? pic_int_value(pic, num) : pic_float_value(pic, num);
}

return pic_false_value(pic);
return string_to_number(pic, str);
}

void
Expand Down
156 changes: 23 additions & 133 deletions extlib/benz/read.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand All @@ -233,140 +220,45 @@ 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;
}

static unsigned
read_uinteger(pic_state *pic, xFILE *file, int c, struct reader_control *PIC_UNUSED(p))
{
unsigned u = 0;

if (! isdigit(c)) {
read_error(pic, "expected one or more digits", pic_list(pic, 1, pic_char_value(pic, c)));
}

u = c - '0';
while (isdigit(c = peek(pic, file))) {
u = u * 10 + next(pic, file) - '0';
}

return u;
return str;
}

static pic_value
read_unsigned(pic_state *pic, xFILE *file, int c, struct reader_control *PIC_UNUSED(p))
read_symbol(pic_state *pic, xFILE *file, int c, struct reader_control *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);
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)
{
return read_unsigned(pic, file, c, p);
}
pic_value str = read_atom(pic, file, c, p), num;

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));
num = pic_funcall(pic, "picrin.base", "string->number", 1, str);
if (! pic_false_p(pic, num)) {
return num;
}
return pic_intern(pic, str);
}

static pic_value
read_minus(pic_state *pic, xFILE *file, int c, struct reader_control *p)
static unsigned
read_uinteger(pic_state *pic, xFILE *file, int c, struct reader_control *PIC_UNUSED(p))
{
pic_value sym;
unsigned u = 0;

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;
if (! isdigit(c)) {
read_error(pic, "expected one or more digits", pic_list(pic, 1, pic_char_value(pic, c)));
}
}

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;
u = c - '0';
while (isdigit(c = peek(pic, file))) {
u = u * 10 + next(pic, file) - '0';
}

return u;
}

static pic_value
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit 5ce271e

Please sign in to comment.