From 9f0dc52934d3ee4e8fe7eddd9abb19380a0e39c8 Mon Sep 17 00:00:00 2001 From: Jesse McDonald Date: Sat, 14 Nov 2009 17:35:34 -0600 Subject: [PATCH] Improve number-reading in preparation for supporting floating-point. --- reader.c | 87 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/reader.c b/reader.c index 50f4e81..0260aaa 100644 --- a/reader.c +++ b/reader.c @@ -21,6 +21,7 @@ typedef struct reader_state static value_t read_one_value(reader_state_t *state); static value_t read_special(reader_state_t *state); static value_t read_list(reader_state_t *state); +static value_t read_fixnum(reader_state_t *state, int radix); static value_t read_number(reader_state_t *state); static value_t read_string(reader_state_t *state); @@ -79,6 +80,7 @@ static value_t read_one_value(reader_state_t *state) case '(': return read_list(state); case '-': + case '+': case '0' ... '9': return read_number(state); case '\"': @@ -215,12 +217,26 @@ static value_t read_list(reader_state_t *state) return list_root.value; } -static value_t read_number(reader_state_t *state) +static short int char_to_digit(int ch) +{ + if (isdigit(ch)) + { + return ch - '0'; + } + else + { + assert(isalpha(ch)); + return 10 + (toupper(ch) - 'A'); + } +} + +static value_t read_fixnum(reader_state_t *state, int radix) { - fixnum_t radix = 10; fixnum_t num = 0; bool negative = false; + assert((0 <= radix) && (radix <= 36)); + if (state->ch == '-') { negative = true; @@ -233,35 +249,49 @@ static value_t read_number(reader_state_t *state) release_assert(isdigit(state->ch)); - if (state->ch == '0') + if (radix == 0) { - next_char(state); - - switch (state->ch) + if (state->ch == '0') { - case 'X': - case 'x': next_char(state); - radix = 16; - break; - case 'B': - case 'b': - next_char(state); - radix = 2; - break; - default: - radix = 8; - break; + + switch (state->ch) + { + case 'X': + case 'x': + next_char(state); + radix = 16; + break; + case 'B': + case 'b': + next_char(state); + radix = 2; + break; + default: + radix = 8; + 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 (isxdigit(state->ch)) + while (isalnum(state->ch)) { - fixnum_t digit = isdigit(state->ch) - ? (state->ch - '0') - : (10 + (toupper(state->ch) - 'A')); + fixnum_t digit = char_to_digit(state->ch); + + if (digit >= radix) + break; - release_assert(digit < radix); release_assert(num <= (FIXNUM_MAX/radix)); num *= radix; @@ -277,6 +307,13 @@ static value_t read_number(reader_state_t *state) return fixnum_value(num); } +static value_t read_number(reader_state_t *state) +{ + value_t v = read_fixnum(state, 0); + release_assert(!issymbol(state->ch)); + return v; +} + static value_t read_string(reader_state_t *state) { char *buffer = (char*)malloc(128); @@ -484,7 +521,7 @@ static value_t read_weak_box(reader_state_t *state) static value_t read_definition(reader_state_t *state) { - fixnum_t ref = get_fixnum(read_number(state)); + fixnum_t ref = get_fixnum(read_fixnum(state, 0)); gc_root_t place_root; value_t v; @@ -514,7 +551,7 @@ static value_t read_placeholder(reader_state_t *state) } else { - return get_placeholder(state, get_fixnum(read_number(state))); + return get_placeholder(state, get_fixnum(read_fixnum(state, 0))); } }