Refactor read_unsigned to prepare for pluggable atod

This commit is contained in:
Doug Currie 2016-01-08 15:55:00 -05:00
parent 8bcfc139f7
commit be33d016e9
3 changed files with 109 additions and 91 deletions

1
.gitignore vendored
View File

@ -11,3 +11,4 @@ GTAGS
_build _build
_static _static
_template _template
.DS_Store

View File

@ -213,6 +213,69 @@ strcpy(char *dst, const char *src)
return d; 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 #endif
#if PIC_ENABLE_STDIO #if PIC_ENABLE_STDIO

View File

@ -237,104 +237,58 @@ read_uinteger(pic_state *pic, struct pic_port *port, int c)
return u; 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 static pic_value
read_unsigned(pic_state *pic, struct pic_port *port, int c) read_unsigned(pic_state *pic, struct pic_port *port, int c)
{ {
unsigned u; #define ATOF_BUF_SIZE (64)
int exp, s, i, e; 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); if (! isdigit(c)) {
read_error(pic, "expected one or more digits", pic_list1(pic, pic_char_value(c)));
switch (peek(pic, port)) { }
#if PIC_ENABLE_LIBC buf[idx++] = (char )c;
case '.': { while (isdigit(c = peek(pic, port)) && idx < ATOF_BUF_SIZE) {
char buf[256]; buf[idx++] = (char )next(pic, port);
i = sprintf(buf, "%d", u); }
buf[i++] = next(pic, port); if ('.' == peek(pic, port) && idx < ATOF_BUF_SIZE) {
while (isdigit(c = peek(pic, port))) { dpe++;
buf[i++] = next(pic, port); buf[idx++] = (char )next(pic, port);
} while (isdigit(c = peek(pic, port)) && idx < ATOF_BUF_SIZE) {
sprintf(buf + i, "e%d", read_suffix(pic, port)); buf[idx++] = (char )next(pic, port);
return pic_float_value(atof(buf)); }
} }
#else c = peek(pic, port);
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);
}
#endif
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: default:
exp = read_suffix(pic, port); break;
if (exp >= 0) {
s = 0;
} else {
exp = -exp;
s = 1;
} }
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);
e = 10; if (dpe == 0 && pic_valid_int(flt))
for (i = 0; exp; ++i) { return pic_int_value((int )flt);
if ((exp & 1) != 0) { return pic_float_value(flt);
u = s ? u / e : (u * e);
}
e *= e;
exp >>= 1;
}
return pic_int_value(u);
}
} }
static pic_value static pic_value
@ -346,7 +300,7 @@ read_number(pic_state *pic, struct pic_port *port, int c)
static pic_value static pic_value
negate(pic_value n) 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)); return pic_int_value(-pic_int(n));
} else { } else {
return pic_float_value(-pic_float(n)); return pic_float_value(-pic_float(n));