Add basic support for reading floating-point values.

No guarantees are made as to the precision.
This commit is contained in:
Jesse D. McDonald 2009-11-17 00:53:36 -06:00
parent bc10f59c6e
commit aa461c8574
1 changed files with 108 additions and 2 deletions

110
reader.c
View File

@ -3,6 +3,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "gc.h"
#include "builtin.h"
@ -309,9 +310,114 @@ static value_t read_fixnum(reader_state_t *state, int radix)
static value_t read_number(reader_state_t *state)
{
value_t v = read_fixnum(state, 0);
bool negative = false;
fixnum_t num = 0;
native_float_t flt;
int radix;
if (state->ch == '-')
{
negative = true;
next_char(state);
}
else if (state->ch == '+')
{
next_char(state);
}
release_assert(isdigit(state->ch));
if (state->ch == '0')
{
next_char(state);
switch (state->ch)
{
case 'X':
case 'x':
next_char(state);
radix = 16;
break;
case 'B':
case 'b':
next_char(state);
radix = 2;
break;
case '0' ... '9':
ungetc(state->ch, state->file);
state->ch = '0';
radix = 8;
break;
default:
ungetc(state->ch, state->file);
state->ch = '0';
radix = 10;
break;
}
if (radix != 8)
{
/* Make sure we have at least one digit; if octal then the '0' counts instead */
release_assert(isalnum(state->ch));
release_assert(char_to_digit(state->ch) < radix);
}
}
else
{
radix = 10;
}
while (isalnum(state->ch))
{
fixnum_t digit = char_to_digit(state->ch);
if (digit >= radix)
break;
release_assert(num <= (FIXNUM_MAX/radix));
num *= radix;
num += digit;
next_char(state);
}
if (negative)
num = -num;
if ((radix != 10) || ((state->ch != '.') && (state->ch != 'E') && (state->ch != 'e')))
{
release_assert(!issymbol(state->ch));
return v;
release_assert((FIXNUM_MIN <= num) && (num <= FIXNUM_MAX));
return fixnum_value(num);
}
/*
* Floating-point. No guarantees as to precision... really should use binary/hex.
*/
flt = num;
if (state->ch == '.')
{
next_char(state);
for (native_float_t pv = negative ? -0.1 : 0.1; isdigit(state->ch); pv /= 10)
{
flt += (state->ch - '0') * pv;
next_char(state);
}
}
if ((state->ch == 'E') || (state->ch == 'e'))
{
next_char(state);
num = read_fixnum(state, 10);
flt *= pow(10, _get_fixnum(num));
}
release_assert(!issymbol(state->ch));
return make_float(flt);
}
static value_t read_string(reader_state_t *state)