simplify number reader

This commit is contained in:
Yuichi Nishiwaki 2016-03-03 19:42:18 +09:00
parent 85b58bd43e
commit 5ce271e9fe
2 changed files with 91 additions and 151 deletions

View File

@ -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

View File

@ -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;
}