klisp

an open source interpreter for the Kernel Programming Language.
git clone http://git.hanabi.in/repos/klisp.git
Log | Files | Refs | README

commit a273cea706e2bbf56c544cd606c3c6f577faa2ac
parent 9237f3ba9e0fba456f75cf351c95bfd9179b34b5
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Tue, 12 Apr 2011 23:59:50 -0300

Some refactoring in ktoken to allow other radix prefixes.

Diffstat:
Msrc/ktoken.c | 53+++++++++++++++++++++++++++++++++++++----------------
Msrc/ktoken.h | 42++++++++++++++++++++++++++----------------
2 files changed, 63 insertions(+), 32 deletions(-)

diff --git a/src/ktoken.c b/src/ktoken.c @@ -14,7 +14,7 @@ ** ** From the Report: ** - Support other number types besides integers and exact infinities -** - Support for complete number syntax (exactness, radix, etc) +** - Support for complete number syntax (inexacts, rationals, reals, complex) ** ** NOT from the Report: ** - Support for unicode (strings, char and symbols). @@ -222,8 +222,11 @@ void ktok_ignore_whitespace_and_comments(klisp_State *K); bool ktok_check_delimiter(klisp_State *K); TValue ktok_read_string(klisp_State *K); TValue ktok_read_special(klisp_State *K); -TValue ktok_read_number(klisp_State *K, bool sign); -TValue ktok_read_maybe_signed_numeric(klisp_State *K); +TValue ktok_read_number(klisp_State *K, bool sign, bool has_exactp, + bool exactp, bool has_radixp, int32_t radix); +TValue ktok_read_maybe_signed_numeric(klisp_State *K, bool has_exactp, + bool exactp, bool has_radixp, + int32_t radix); TValue ktok_read_identifier(klisp_State *K); int ktok_read_until_delimiter(klisp_State *K); @@ -271,9 +274,11 @@ TValue ktok_read_token (klisp_State *K) return ktok_read_special(K); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - return ktok_read_number(K, true); /* positive number */ + /* positive number, no exactness or radix indicator */ + return ktok_read_number(K, true, false, false, false, 10); case '+': case '-': - return ktok_read_maybe_signed_numeric(K); + /* signed number, no exactness or radix indicator */ + return ktok_read_maybe_signed_numeric(K, false, false, false, 10); case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': @@ -360,9 +365,10 @@ int ktok_read_until_delimiter(klisp_State *K) /* ** Numbers -** TEMP: for now, only integers in base 10 +** TEMP: for now, only integers, ignore exactness */ -TValue ktok_read_number(klisp_State *K, bool is_pos) +TValue ktok_read_number(klisp_State *K, bool is_pos, bool has_exactp, + bool exactp, bool has_radixp, int32_t radix) { uint32_t fixint_res = 0; bool is_fixint = true; @@ -370,15 +376,21 @@ TValue ktok_read_number(klisp_State *K, bool is_pos) while(!ktok_check_delimiter(K)) { /* NOTE: can't be eof because it's a delimiter */ - char ch = (char) ktok_getc(K); - if (!ktok_is_numeric(ch)) { - ktok_error(K, "Not a digit found in number"); + /* both is_digit and digit_value only recognize lowercase + for hex */ + char ch = tolower((char) ktok_getc(K)); + + if (!ktok_is_digit(ch, radix)) { + /* TODO show the char */ + ktok_error(K, "Invalid char found in number"); /* avoid warning */ return KINERT; } int32_t new_digit = ktok_digit_value(ch); - if (is_fixint && CAN_ADD_DIGIT(fixint_res, !is_pos, new_digit)) { - fixint_res = fixint_res * 10 + new_digit; + + if (is_fixint && can_add_digit(fixint_res, !is_pos, new_digit, + radix)) { + fixint_res = fixint_res * radix + new_digit; } else { if (is_fixint) { /* up to the last loop was fixint, but can't be anymore. @@ -389,7 +401,7 @@ TValue ktok_read_number(klisp_State *K, bool is_pos) bigint_res = kbigint_new(K, false, fixint_res); /* GC: root bigint_res */ } - kbigint_add_digit(K, bigint_res, 10, new_digit); + kbigint_add_digit(K, bigint_res, radix, new_digit); } } @@ -404,18 +416,27 @@ TValue ktok_read_number(klisp_State *K, bool is_pos) } } -TValue ktok_read_maybe_signed_numeric(klisp_State *K) +TValue ktok_read_maybe_signed_numeric(klisp_State *K, bool has_exactp, + bool exactp, bool has_radixp, + int32_t radix) { /* NOTE: can't be eof, it's either '+' or '-' */ char ch = (char) ktok_getc(K); if (ktok_check_delimiter(K)) { + if (has_exactp || has_radixp) { + ktok_error(K, "No digit found in number"); + /* avoid warning */ + return KINERT; + } + ks_tbadd(K, ch); ks_tbadd(K, '\0'); TValue new_sym = ksymbol_new_i(K, ks_tbget_buffer(K), 1); ks_tbclear(K); return new_sym; } else { - return ktok_read_number(K, ch == '+'); + return ktok_read_number(K, ch == '+', has_exactp, exactp, + has_radixp, radix); } } @@ -604,7 +625,7 @@ TValue ktok_read_special(klisp_State *K) } int new_digit = ktok_digit_value(ch); - if (CAN_ADD_DIGIT(res, false, new_digit)) { + if (can_add_digit(res, false, new_digit, 10)) { res = res * 10 + new_digit; } else { ktok_error(K, "IMP. RESTRICTION: shared token too big"); diff --git a/src/ktoken.h b/src/ktoken.h @@ -27,6 +27,12 @@ void clear_shared_dict(klisp_State *K); representation as an identifier */ /* REFACTOR: think out a better interface to all this */ +/* +** Char set contains macro interface +*/ +#define KCHS_OCTANT(ch) ((ch) >> 5) +#define KCHS_BIT(ch) (1 << ((ch) & 0x1f)) + /* Each bit correspond to a char in the 0-255 range */ typedef uint32_t kcharset[8]; @@ -34,10 +40,8 @@ extern kcharset ktok_alphabetic, ktok_numeric, ktok_whitespace; extern kcharset ktok_delimiter, ktok_extended, ktok_subsequent; #define ktok_is_alphabetic(chi_) kcharset_contains(ktok_alphabetic, chi_) -/* TODO: add is_digit, that takes the base as parameter */ #define ktok_is_numeric(chi_) kcharset_contains(ktok_numeric, chi_) -/* TODO: add hex digits */ -#define ktok_digit_value(ch_) (ch_ - '0') + #define ktok_is_whitespace(chi_) kcharset_contains(ktok_whitespace, chi_) #define ktok_is_delimiter(chi_) ((chi_) == EOF || \ kcharset_contains(ktok_delimiter, chi_)) @@ -47,20 +51,26 @@ extern kcharset ktok_delimiter, ktok_extended, ktok_subsequent; ({ unsigned char ch__ = (unsigned char) (ch_); \ kch_[KCHS_OCTANT(ch__)] & KCHS_BIT(ch__); }) -/* TODO: add other bases */ -/* This takes the args in sign magnitude form (sign_ & res_), - but must work for any representation of negative numbers */ -#define CAN_ADD_DIGIT(res_, sign_, new_digit_) \ - ({ uint32_t res = (res_); \ - uint32_t digit = (new_digit_); \ - (sign_)? res <= -(INT32_MIN + digit) / 10 : \ - res <= (INT32_MAX - digit) / 10;}) +/* NOTE: only lowercase chars for hexa */ +inline bool ktok_is_digit(char ch, int32_t radix) +{ + return (ktok_is_numeric(ch) && (ch - '0') < radix) || + (ktok_is_alphabetic(ch) && (10 + (ch - 'a')) < radix); +} -/* -** Char set contains macro interface -*/ -#define KCHS_OCTANT(ch) ((ch) >> 5) -#define KCHS_BIT(ch) (1 << ((ch) & 0x1f)) +inline int32_t ktok_digit_value(char ch) +{ + return (ch <= '9')? ch - '0' : 10 + (ch - 'a'); +} + +/* This takes the args in sign magnitude form (sign & res), + but must work for any representation of negative numbers */ +inline bool can_add_digit(uint32_t res, bool sign, uint32_t new_digit, + int32_t radix) +{ + return (sign)? res <= -(INT32_MIN + new_digit) / radix : + res <= (INT32_MAX - new_digit) / radix; +} #endif