Add basic support for reading floating-point values.
No guarantees are made as to the precision.
This commit is contained in:
parent
bc10f59c6e
commit
aa461c8574
110
reader.c
110
reader.c
|
|
@ -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));
|
||||
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 v;
|
||||
return make_float(flt);
|
||||
}
|
||||
|
||||
static value_t read_string(reader_state_t *state)
|
||||
|
|
|
|||
Loading…
Reference in New Issue