klisp

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

commit 33b87dafccd559d25f27b393fde1b434701e88cd
parent e7b96a3fb856e0d07d8704b675a08cf406495326
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Sat,  9 Apr 2011 17:58:34 -0300

Added reading of bigints (still not tested, need writing of bigints first!). Reading of fixints between INT32_MIN & INT32_MAX works ok.

Diffstat:
Msrc/Makefile | 2+-
Msrc/kinteger.c | 18+++++++++++++-----
Msrc/kinteger.h | 6+++++-
Msrc/ktoken.c | 37++++++++++++++++++++++++++++++-------
Msrc/ktoken.h | 10++++++++--
5 files changed, 57 insertions(+), 16 deletions(-)

diff --git a/src/Makefile b/src/Makefile @@ -44,7 +44,7 @@ klisp.o: klisp.c klisp.h kobject.h kread.h kwrite.h klimits.h kstate.h kmem.h \ kapplicative.h koperative.h keval.h krepl.h kobject.o: kobject.c kobject.h klisp.h ktoken.o: ktoken.c ktoken.h kobject.h kstate.h kpair.h kstring.h ksymbol.h \ - kerror.h klisp.h + kerror.h klisp.h kinteger.h kinteger.o: kinteger.c kinteger.h kobject.h kstate.h kmem.h klisp.h kpair.o: kpair.c kpair.h kobject.h kstate.h kmem.h klisp.h kstring.o: kstring.c kstring.h kobject.h kstate.h kmem.h klisp.h diff --git a/src/kinteger.c b/src/kinteger.c @@ -26,7 +26,9 @@ Bigint_Node *make_new_node(klisp_State *K, uint32_t digit) return node; } -TValue kbigint_new(klisp_State *K, int32_t fixint) +/* for now used only for reading */ +/* NOTE: is uint to allow INT32_MIN as positive argument in read */ +TValue kbigint_new(klisp_State *K, bool sign, uint32_t digit) { Bigint *new_bigint = klispM_new(K, Bigint); @@ -45,9 +47,9 @@ TValue kbigint_new(klisp_State *K, int32_t fixint) new_bigint->sign_size = 0; new_bigint->first = new_bigint->last = NULL; - Bigint_Node *node = make_new_node(K, fixint); + Bigint_Node *node = make_new_node(K, digit); new_bigint->first = new_bigint->last = node; - new_bigint->sign_size = fixint < 0? -1 : 1; + new_bigint->sign_size = sign? -1 : 1; return gc2bigint(new_bigint); } @@ -58,7 +60,6 @@ TValue kbigint_new(klisp_State *K, int32_t fixint) void kbigint_add_digit(klisp_State *K, TValue tv_bigint, int32_t base, int32_t digit) { - /* GC: root tv_bigint */ Bigint *bigint = tv2bigint(tv_bigint); /* iterate in little endian mode */ bind_iter(iter, bigint, false); @@ -77,6 +78,13 @@ void kbigint_add_digit(klisp_State *K, TValue tv_bigint, int32_t base, if (carry != 0) { /* must add one node to the bigint */ - kbigint_add_node(bigint, make_new_node(K, carry)); + kbigint_add_node(bigint, make_new_node(K, (uint32_t) carry)); } } + +/* Mutate the bigint to have the opposite sign, used in read */ +void kbigint_invert_sign(TValue tv_bigint) +{ + Bigint *bigint = tv2bigint(tv_bigint); + bigint->sign_size = -bigint->sign_size; +} diff --git a/src/kinteger.h b/src/kinteger.h @@ -15,7 +15,8 @@ #include "kstate.h" /* for now used only for reading */ -TValue kbigint_new(klisp_State *K, int32_t fixint); +/* NOTE: is uint and has flag to allow INT32_MIN as positive argument */ +TValue kbigint_new(klisp_State *K, bool sign, uint32_t digit); /* Create a stack allocated bigints from a fixint, @@ -37,4 +38,7 @@ TValue kbigint_new(klisp_State *K, int32_t fixint); void kbigint_add_digit(klisp_State *K, TValue tv_bigint, int32_t base, int32_t digit); +/* Mutate the bigint to have the opposite sign, used in read */ +void kbigint_invert_sign(TValue tv_bigint); + #endif diff --git a/src/ktoken.c b/src/ktoken.c @@ -35,6 +35,7 @@ #include "ktoken.h" #include "kobject.h" #include "kstate.h" +#include "kinteger.h" #include "kpair.h" #include "kstring.h" #include "ksymbol.h" @@ -359,11 +360,13 @@ int ktok_read_until_delimiter(klisp_State *K) /* ** Numbers -** TEMP: for now, only fixints in base 10 +** TEMP: for now, only integers in base 10 */ TValue ktok_read_number(klisp_State *K, bool is_pos) { - int32_t res = 0; + uint32_t fixint_res = 0; + bool is_fixint = true; + TValue bigint_res; while(!ktok_check_delimiter(K)) { /* NOTE: can't be eof because it's a delimiter */ @@ -373,12 +376,32 @@ TValue ktok_read_number(klisp_State *K, bool is_pos) /* avoid warning */ return KINERT; } - res = res * 10 + ktok_digit_value(ch); + 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; + } else { + if (is_fixint) { + /* up to the last loop was fixint, but can't be anymore. + Create a bigint and mutate to add the new digits. This + avoids unnecessary consing and discarding values that would + occur if it used the regular bigint+ and bigint* */ + is_fixint = false; + bigint_res = kbigint_new(K, false, fixint_res); + /* GC: root bigint_res */ + } + kbigint_add_digit(K, bigint_res, 10, new_digit); + } } - if (!is_pos) - res = -res; - return i2tv(res); + if (is_fixint) { + int32_t fixint = (is_pos)? (int32_t) fixint_res : + (int32_t) -((int64_t) fixint_res); + return i2tv(fixint); + } else { + if (!is_pos) + kbigint_invert_sign(bigint_res); + return bigint_res; + } } TValue ktok_read_maybe_signed_numeric(klisp_State *K) @@ -581,7 +604,7 @@ TValue ktok_read_special(klisp_State *K) } int new_digit = ktok_digit_value(ch); - if (CAN_ADD_DIGIT(res, new_digit)) { + if (CAN_ADD_DIGIT(res, false, new_digit)) { 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 @@ -48,8 +48,14 @@ extern kcharset ktok_delimiter, ktok_extended, ktok_subsequent; kch_[KCHS_OCTANT(ch__)] & KCHS_BIT(ch__); }) /* TODO: add other bases */ -#define CAN_ADD_DIGIT(res, new_digit) \ - ((res) <= (INT32_MAX - new_digit) / 10) +/* 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;}) + /* ** Char set contains macro interface