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 <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "gc.h"
|
#include "gc.h"
|
||||||
#include "builtin.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)
|
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(!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)
|
static value_t read_string(reader_state_t *state)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue