diff options
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | builtin.cpp | 334 | ||||
-rw-r--r-- | consts.cpp | 3 | ||||
-rw-r--r-- | consts.h | 3 | ||||
-rw-r--r-- | eval.cpp | 28 | ||||
-rw-r--r-- | gc.cpp | 113 | ||||
-rw-r--r-- | gc.h | 32 | ||||
-rw-r--r-- | main.cpp | 32 | ||||
-rw-r--r-- | parser.cpp | 1 | ||||
-rw-r--r-- | test/q.scm | 69 | ||||
-rw-r--r-- | types.cpp | 373 | ||||
-rw-r--r-- | types.h | 80 |
12 files changed, 794 insertions, 281 deletions
@@ -1,8 +1,8 @@ -sonsi: main.o parser.o builtin.o model.o eval.o exc.o consts.o types.o +sonsi: main.o parser.o builtin.o model.o eval.o exc.o consts.o types.o gc.o g++ -o sonsi $^ -pg -lgmp .cpp.o: - g++ $< -c -g -pg -DGMP_SUPPORT -Wall -O2 + g++ $< -c -O2 -DGMP_SUPPORT -Wall clean: rm -f *.o @@ -13,3 +13,6 @@ db: cdb: cgdb sonsi + +run: + ./sonsi diff --git a/builtin.cpp b/builtin.cpp index 8d3e21d..f1e4c19 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -7,6 +7,7 @@ #include "model.h" #include "exc.h" #include "types.h" +#include "gc.h" using std::stringstream; @@ -45,7 +46,9 @@ Pair *SpecialOptIf::call(Pair *args, Environment * &envt, { if (ret_info->state == empty_list) { - *top_ptr++ = TO_PAIR(args->cdr)->car; + delete *top_ptr; + *top_ptr++ = gc.attach(TO_PAIR(args->cdr)->car); + gc.expose(args); return ret_addr->next; // Move to the next instruction } else @@ -59,30 +62,38 @@ Pair *SpecialOptIf::call(Pair *args, Environment * &envt, { second->next = NULL; // Undo pop and invoke again - top_ptr += 2; + gc.attach(static_cast<EvalObj*>(*(++top_ptr))); + top_ptr++; ret_info->state = empty_list; + gc.expose(args); return second; } else if (third != empty_list) { third->next = NULL; // Undo pop and invoke again - top_ptr += 2; + gc.attach(static_cast<EvalObj*>(*(++top_ptr))); + top_ptr++; ret_info->state = empty_list; + gc.expose(args); return third; } else { - *top_ptr++ = unspec_obj; + delete *top_ptr; + *top_ptr++ = gc.attach(unspec_obj); + gc.expose(args); return ret_addr->next; } } } else { - top_ptr += 2; + gc.attach(static_cast<EvalObj*>(*(++top_ptr))); + top_ptr++; ret_info->state = TO_PAIR(TO_PAIR(ret_addr->car)->cdr); ret_info->state->next = NULL; + gc.expose(args); return ret_info->state; } throw NormalError(INT_ERR); @@ -160,7 +171,9 @@ Pair *SpecialOptLambda::call(Pair *args, Environment * &envt, for (Pair *ptr = body; ptr != empty_list; ptr = TO_PAIR(ptr->cdr)) ptr->next = NULL; // Make each expression isolated - *top_ptr++ = new ProcObj(body, envt, params); + delete *top_ptr; + *top_ptr++ = gc.attach(new ProcObj(body, envt, params)); + gc.expose(args); return ret_addr->next; // Move to the next instruction } @@ -195,9 +208,11 @@ Pair *SpecialOptDefine::call(Pair *args, Environment * &envt, { if (!ret_info->state) { - top_ptr += 2; + gc.attach(static_cast<EvalObj*>(*(++top_ptr))); + top_ptr++; ret_info->state = TO_PAIR(TO_PAIR(pc->cdr)->cdr); ret_info->state->next = NULL; + gc.expose(args); return ret_info->state; } if (!first->is_sym_obj()) @@ -233,7 +248,9 @@ Pair *SpecialOptDefine::call(Pair *args, Environment * &envt, obj = new ProcObj(body, envt, params); } envt->add_binding(id, obj); - *top_ptr++ = unspec_obj; + delete *top_ptr; + *top_ptr++ = gc.attach(unspec_obj); + gc.expose(args); return ret_addr->next; } @@ -264,9 +281,11 @@ Pair *SpecialOptSet::call(Pair *args, Environment * &envt, if (!ret_info->state) { - top_ptr += 2; + gc.attach(static_cast<EvalObj*>(*(++top_ptr))); + top_ptr++; ret_info->state = TO_PAIR(TO_PAIR(pc->cdr)->cdr); ret_info->state->next = NULL; + gc.expose(args); return ret_info->state; } @@ -277,7 +296,9 @@ Pair *SpecialOptSet::call(Pair *args, Environment * &envt, bool flag = envt->add_binding(id, TO_PAIR(args->cdr)->car, false); if (!flag) throw TokenError(id->ext_repr(), RUN_ERR_UNBOUND_VAR); - *top_ptr++ = unspec_obj; + delete *top_ptr; + *top_ptr++ = gc.attach(unspec_obj); + gc.expose(args); return ret_addr->next; } @@ -292,7 +313,9 @@ Pair *SpecialOptQuote::call(Pair *args, Environment * &envt, Continuation * &cont, FrameObj ** &top_ptr) { Pair *ret_addr = static_cast<RetAddr*>(*top_ptr)->addr; Pair *pc = static_cast<Pair*>(ret_addr->car); - *top_ptr++ = TO_PAIR(pc->cdr)->car; + delete *top_ptr; + *top_ptr++ = gc.attach(TO_PAIR(pc->cdr)->car); + gc.expose(args); return ret_addr->next; } @@ -310,14 +333,20 @@ Pair *SpecialOptEval::call(Pair *args, Environment * &envt, Pair *ret_addr = ret_info->addr; if (ret_info->state) { - *top_ptr++ = TO_PAIR(args->cdr)->car; + gc.expose(ret_info->state); // Exec done + delete *top_ptr; + *top_ptr++ = gc.attach(TO_PAIR(args->cdr)->car); + gc.expose(args); return ret_addr->next; // Move to the next instruction } else { - top_ptr += 2; + gc.attach(static_cast<EvalObj*>(*(++top_ptr))); + top_ptr++; ret_info->state = TO_PAIR(args->cdr); + gc.attach(ret_info->state); // Or it will be released ret_info->state->next = NULL; + gc.expose(args); return ret_info->state; } throw NormalError(INT_ERR); @@ -336,14 +365,18 @@ Pair *SpecialOptAnd::call(Pair *args, Environment * &envt, Pair *pc = static_cast<Pair*>(ret_addr->car); if (pc->cdr == empty_list) { - *top_ptr++ = new BoolObj(true); + delete *top_ptr; + *top_ptr++ = gc.attach(new BoolObj(true)); + gc.expose(args); return ret_addr->next; } if (!ret_info->state) { - top_ptr += 2; + gc.attach(static_cast<EvalObj*>(*(++top_ptr))); + top_ptr++; ret_info->state = TO_PAIR(pc->cdr); ret_info->state->next = NULL; + gc.expose(args); return ret_info->state; } EvalObj *ret = TO_PAIR(args->cdr)->car; @@ -351,20 +384,26 @@ Pair *SpecialOptAnd::call(Pair *args, Environment * &envt, { if (ret_info->state->cdr == empty_list) // the last member { - *top_ptr++ = ret; + delete *top_ptr; + *top_ptr++ = gc.attach(ret); + gc.expose(args); return ret_addr->next; } else { - top_ptr += 2; + gc.attach(static_cast<EvalObj*>(*(++top_ptr))); + top_ptr++; ret_info->state = TO_PAIR(ret_info->state->cdr); ret_info->state->next = NULL; + gc.expose(args); return ret_info->state; } } else { - *top_ptr++ = ret; + delete *top_ptr; + *top_ptr++ = gc.attach(ret); + gc.expose(args); return ret_addr->next; } throw NormalError(INT_ERR); @@ -383,14 +422,18 @@ Pair *SpecialOptOr::call(Pair *args, Environment * &envt, Pair *pc = static_cast<Pair*>(ret_addr->car); if (pc->cdr == empty_list) { - *top_ptr++ = new BoolObj(false); + delete *top_ptr; + *top_ptr++ = gc.attach(new BoolObj(false)); + gc.expose(args); return ret_addr->next; } if (!ret_info->state) { - top_ptr += 2; + gc.attach(static_cast<EvalObj*>(*(++top_ptr))); + top_ptr++; ret_info->state = TO_PAIR(pc->cdr); ret_info->state->next = NULL; + gc.expose(args); return ret_info->state; } EvalObj *ret = TO_PAIR(args->cdr)->car; @@ -398,20 +441,26 @@ Pair *SpecialOptOr::call(Pair *args, Environment * &envt, { if (ret_info->state->cdr == empty_list) // the last member { - *top_ptr++ = ret; + delete *top_ptr; + *top_ptr++ = gc.attach(ret); + gc.expose(args); return ret_addr->next; } else { - top_ptr += 2; + gc.attach(static_cast<EvalObj*>(*(++top_ptr))); + top_ptr++; ret_info->state = TO_PAIR(ret_info->state->cdr); ret_info->state->next = NULL; + gc.expose(args); return ret_info->state; } } else { - *top_ptr++ = ret; + delete *top_ptr; + *top_ptr++ = gc.attach(ret); + gc.expose(args); return ret_addr->next; } throw NormalError(INT_ERR); @@ -421,8 +470,9 @@ SpecialOptApply::SpecialOptApply() : SpecialOptObj("apply") {} void SpecialOptApply::prepare(Pair *pc) {} -Pair *SpecialOptApply::call(Pair *args, Environment * &envt, +Pair *SpecialOptApply::call(Pair *_args, Environment * &envt, Continuation * &cont, FrameObj ** &top_ptr) { + Pair *args = _args; top_ptr++; // Recover the return address if (args->cdr == empty_list) throw TokenError(name, RUN_ERR_WRONG_NUM_OF_ARGS); @@ -431,13 +481,13 @@ Pair *SpecialOptApply::call(Pair *args, Environment * &envt, if (!args->car->is_opt_obj()) throw TokenError("an operator", RUN_ERR_WRONG_TYPE); - *top_ptr++ = args->car; // Push the operator into the stack - args = TO_PAIR(args->cdr); // Examine arguments + *top_ptr++ = gc.attach(args->car); // Push the operator into the stack + args = TO_PAIR(args->cdr); // Examine arguments if (args == empty_list) throw TokenError(name, RUN_ERR_WRONG_NUM_OF_ARGS); for (; args->cdr != empty_list; args = TO_PAIR(args->cdr)) - *top_ptr++ = args->car; // Add leading arguments: arg_1 ... + *top_ptr++ = gc.attach(args->car); // Add leading arguments: arg_1 ... if (args->car != empty_list) // args->car is the trailing args { @@ -448,7 +498,7 @@ Pair *SpecialOptApply::call(Pair *args, Environment * &envt, EvalObj *nptr; for (;;) { - *top_ptr++ = args->car; + *top_ptr++ = gc.attach(args->car); if ((nptr = args->cdr)->is_pair_obj()) args = TO_PAIR(nptr); else break; @@ -457,6 +507,7 @@ Pair *SpecialOptApply::call(Pair *args, Environment * &envt, throw TokenError("a list", RUN_ERR_WRONG_TYPE); } // force the invocation, so that the desired operator will take over + gc.expose(_args); return NULL; } @@ -468,8 +519,9 @@ void SpecialOptForce::prepare(Pair *pc) { throw TokenError(name, RUN_ERR_WRONG_NUM_OF_ARGS); } -Pair *SpecialOptForce::call(Pair *args, Environment * &envt, +Pair *SpecialOptForce::call(Pair *_args, Environment * &envt, Continuation * &cont, FrameObj ** &top_ptr) { + Pair *args = _args; args = TO_PAIR(args->cdr); RetAddr *ret_info = static_cast<RetAddr*>(*top_ptr); Pair *ret_addr = ret_info->addr; @@ -477,7 +529,9 @@ Pair *SpecialOptForce::call(Pair *args, Environment * &envt, { EvalObj *mem = args->car; prom->feed_mem(mem); - *top_ptr++ = mem; + delete *top_ptr; + *top_ptr++ = gc.attach(mem); + gc.expose(_args); return ret_addr->next; // Move to the next instruction } else @@ -488,14 +542,18 @@ Pair *SpecialOptForce::call(Pair *args, Environment * &envt, EvalObj *mem = prom->get_mem(); if (mem) // fetch from memorized result { - *top_ptr++ = mem; + delete *top_ptr; + *top_ptr++ = gc.attach(mem); + gc.expose(_args); return ret_addr->next; } else // force { - top_ptr += 2; + gc.attach(static_cast<EvalObj*>(*(++top_ptr))); + top_ptr++; ret_info->state = prom->get_entry(); ret_info->state->next = NULL; + gc.expose(_args); return ret_info->state; } } @@ -514,7 +572,9 @@ Pair *SpecialOptDelay::call(Pair *args, Environment * &envt, Continuation * &cont, FrameObj ** &top_ptr) { Pair *ret_addr = static_cast<RetAddr*>(*top_ptr)->addr; Pair *pc = static_cast<Pair*>(ret_addr->car); - *top_ptr++ = new PromObj(TO_PAIR(pc->cdr)->car); + delete *top_ptr; + *top_ptr++ = gc.attach(new PromObj(TO_PAIR(pc->cdr)->car)); + gc.expose(args); return ret_addr->next; // Move to the next instruction } @@ -562,7 +622,7 @@ BUILTIN_PROC_DEF(pair_cdr) { BUILTIN_PROC_DEF(make_list) { - return args; + return gc.attach(args); // Or it will be GCed } BUILTIN_PROC_DEF(num_add) { @@ -574,11 +634,16 @@ BUILTIN_PROC_DEF(num_add) { throw TokenError("a number", RUN_ERR_WRONG_TYPE); opr = static_cast<NumObj*>(args->car); NumObj *_res = res; - if (_res->level < opr->level) - opr = _res->convert(opr); + if (res->level < opr->level) + { + res->add(opr = res->convert(opr)); + delete opr; + } else - _res = opr->convert(_res); - res = _res->add(opr); + { + (res = opr->convert(res))->add(opr); + delete _res; + } } return res; } @@ -589,12 +654,15 @@ BUILTIN_PROC_DEF(num_sub) { throw TokenError("a number", RUN_ERR_WRONG_TYPE); NumObj *res = static_cast<NumObj*>(args->car), *opr; + res = res->clone(); args = TO_PAIR(args->cdr); if (args == empty_list) { - IntNumObj _zero(0); - NumObj *zero = res->convert(&_zero); - return zero->sub(res); + IntNumObj *_zero = new IntNumObj(0); + NumObj *zero = res->convert(_zero); + if (zero != _zero) delete _zero; + zero->sub(res); + return zero; } for (; args != empty_list; args = TO_PAIR(args->cdr)) { @@ -603,16 +671,20 @@ BUILTIN_PROC_DEF(num_sub) { opr = static_cast<NumObj*>(args->car); // upper type conversion NumObj *_res = res; - if (_res->level < opr->level) - opr = _res->convert(opr); + if (res->level < opr->level) + { + res->sub(opr = res->convert(opr)); + delete opr; + } else - _res = opr->convert(_res); - res = _res->sub(opr); + { + (res = opr->convert(res))->sub(opr); + delete _res; + } } return res; } - BUILTIN_PROC_DEF(num_mul) { // ARGS_AT_LEAST_ONE; NumObj *res = new IntNumObj(1), *opr; // the most accurate type @@ -622,11 +694,16 @@ BUILTIN_PROC_DEF(num_mul) { throw TokenError("a number", RUN_ERR_WRONG_TYPE); opr = static_cast<NumObj*>(args->car); NumObj *_res = res; - if (_res->level < opr->level) - opr = _res->convert(opr); + if (res->level < opr->level) + { + res->mul(opr = res->convert(opr)); + delete opr; + } else - _res = opr->convert(_res); - res = _res->mul(opr); + { + (res = opr->convert(res))->mul(opr); + delete _res; + } } return res; } @@ -635,13 +712,20 @@ BUILTIN_PROC_DEF(num_div) { ARGS_AT_LEAST_ONE; if (!args->car->is_num_obj()) throw TokenError("a number", RUN_ERR_WRONG_TYPE); + NumObj *res = static_cast<NumObj*>(args->car), *opr; + if (res->level > NUM_LVL_RAT) + res = new RatNumObj(static_cast<IntNumObj*>(res)->val); + else res = res->clone(); + args = TO_PAIR(args->cdr); if (args == empty_list) { - IntNumObj _one(1); - NumObj *one = res->convert(&_one); - return one->div(res); + IntNumObj *_one = new IntNumObj(1); + NumObj *one = res->convert(_one); + if (one != _one) delete _one; + one->div(res); + return one; } for (; args != empty_list; args = TO_PAIR(args->cdr)) { @@ -650,15 +734,21 @@ BUILTIN_PROC_DEF(num_div) { opr = static_cast<NumObj*>(args->car); // upper type conversion NumObj *_res = res; - if (_res->level < opr->level) - opr = _res->convert(opr); + if (res->level < opr->level) + { + res->div(opr = res->convert(opr)); + delete opr; + } else - _res = opr->convert(_res); - res = _res->div(opr); + { + (res = opr->convert(res))->div(opr); + delete _res; + } } return res; } + BUILTIN_PROC_DEF(num_le) { if (args == empty_list) return new BoolObj(true); @@ -675,16 +765,28 @@ BUILTIN_PROC_DEF(num_le) { opr = static_cast<NumObj*>(args->car); // upper type conversion if (last->level < opr->level) - opr = last->convert(opr); + { + if (!last->le(opr = last->convert(opr))) + { + delete opr; + return new BoolObj(false); + } + else delete opr; + } else - last = opr->convert(last); - if (!last->le(opr)) - return new BoolObj(false); + { + if (!(last = opr->convert(last))->le(opr)) + { + delete last; + return new BoolObj(false); + } + else delete last; + } } return new BoolObj(true); } -BUILTIN_PROC_DEF(num_ge) { +BUILTIN_PROC_DEF(num_lt) { if (args == empty_list) return new BoolObj(true); // zero arguments @@ -700,17 +802,28 @@ BUILTIN_PROC_DEF(num_ge) { opr = static_cast<NumObj*>(args->car); // upper type conversion if (last->level < opr->level) - opr = last->convert(opr); + { + if (!last->lt(opr = last->convert(opr))) + { + delete opr; + return new BoolObj(false); + } + else delete opr; + } else - last = opr->convert(last); - if (!last->ge(opr)) - return new BoolObj(false); + { + if (!(last = opr->convert(last))->lt(opr)) + { + delete last; + return new BoolObj(false); + } + else delete last; + } } return new BoolObj(true); } - -BUILTIN_PROC_DEF(num_lt) { +BUILTIN_PROC_DEF(num_ge) { if (args == empty_list) return new BoolObj(true); // zero arguments @@ -726,11 +839,23 @@ BUILTIN_PROC_DEF(num_lt) { opr = static_cast<NumObj*>(args->car); // upper type conversion if (last->level < opr->level) - opr = last->convert(opr); + { + if (!last->ge(opr = last->convert(opr))) + { + delete opr; + return new BoolObj(false); + } + else delete opr; + } else - last = opr->convert(last); - if (!last->lt(opr)) - return new BoolObj(false); + { + if (!(last = opr->convert(last))->ge(opr)) + { + delete last; + return new BoolObj(false); + } + else delete last; + } } return new BoolObj(true); } @@ -751,11 +876,23 @@ BUILTIN_PROC_DEF(num_gt) { opr = static_cast<NumObj*>(args->car); // upper type conversion if (last->level < opr->level) - opr = last->convert(opr); + { + if (!last->gt(opr = last->convert(opr))) + { + delete opr; + return new BoolObj(false); + } + else delete opr; + } else - last = opr->convert(last); - if (!last->gt(opr)) - return new BoolObj(false); + { + if (!(last = opr->convert(last))->gt(opr)) + { + delete last; + return new BoolObj(false); + } + else delete last; + } } return new BoolObj(true); } @@ -776,15 +913,28 @@ BUILTIN_PROC_DEF(num_eq) { opr = static_cast<NumObj*>(args->car); // upper type conversion if (last->level < opr->level) - opr = last->convert(opr); + { + if (!last->eq(opr = last->convert(opr))) + { + delete opr; + return new BoolObj(false); + } + else delete opr; + } else - last = opr->convert(last); - if (!last->eq(opr)) - return new BoolObj(false); + { + if (!(last = opr->convert(last))->eq(opr)) + { + delete last; + return new BoolObj(false); + } + else delete last; + } } return new BoolObj(true); } + BUILTIN_PROC_DEF(bool_not) { ARGS_EXACTLY_ONE; return new BoolObj(!args->car->is_true()); @@ -1148,7 +1298,9 @@ BUILTIN_PROC_DEF(is_integer) { BUILTIN_PROC_DEF(num_abs) { ARGS_EXACTLY_ONE; CHECK_NUMBER(args->car); - return static_cast<NumObj*>(args->car)->abs(); + NumObj* num = static_cast<NumObj*>(args->car)->clone(); + num->abs(); + return num; } BUILTIN_PROC_DEF(num_mod) { @@ -1159,7 +1311,9 @@ BUILTIN_PROC_DEF(num_mod) { NumObj* b = static_cast<NumObj*>(TO_PAIR(args->cdr)->car); CHECK_INT(a); CHECK_INT(b); - return static_cast<IntNumObj*>(a)->mod(b); + NumObj* res = a->clone(); + static_cast<IntNumObj*>(res)->mod(b); + return res; } BUILTIN_PROC_DEF(num_rem) { @@ -1170,7 +1324,9 @@ BUILTIN_PROC_DEF(num_rem) { NumObj* b = static_cast<NumObj*>(TO_PAIR(args->cdr)->car); CHECK_INT(a); CHECK_INT(b); - return static_cast<IntNumObj*>(a)->rem(b); + NumObj* res = a->clone(); + static_cast<IntNumObj*>(res)->rem(b); + return res; } BUILTIN_PROC_DEF(num_quo) { @@ -1181,12 +1337,14 @@ BUILTIN_PROC_DEF(num_quo) { NumObj* b = static_cast<NumObj*>(TO_PAIR(args->cdr)->car); CHECK_INT(a); CHECK_INT(b); - return static_cast<IntNumObj*>(a)->quo(b); + NumObj* res = a->clone(); + static_cast<IntNumObj*>(res)->div(b); + return res; } BUILTIN_PROC_DEF(num_gcd) { // ARGS_AT_LEAST_ONE; - NumObj *res = new IntNumObj(0); + IntNumObj *res = new IntNumObj(0); IntNumObj *opr; for (;args != empty_list; args = TO_PAIR(args->cdr)) { @@ -1194,14 +1352,14 @@ BUILTIN_PROC_DEF(num_gcd) { CHECK_INT(static_cast<NumObj*>(args->car)); opr = static_cast<IntNumObj*>(args->car); - res = opr->gcd(res); + res->gcd(opr); } return res; } BUILTIN_PROC_DEF(num_lcm) { // ARGS_AT_LEAST_ONE; - NumObj *res = new IntNumObj(1); + IntNumObj *res = new IntNumObj(1); IntNumObj *opr; for (;args != empty_list; args = TO_PAIR(args->cdr)) { @@ -1209,7 +1367,7 @@ BUILTIN_PROC_DEF(num_lcm) { CHECK_INT(static_cast<NumObj*>(args->car)); opr = static_cast<IntNumObj*>(args->car); - res = opr->lcm(res); + res->lcm(opr); } return res; } @@ -19,5 +19,6 @@ const char *ERR_MSG[] = { "Queue overflowed: the expected expansion is too long!", "%s stack overflowed!", "Numeric overflow!", - "Value out of range" + "Value out of range", + "GC overflow!" }; @@ -20,7 +20,8 @@ enum ErrCode { RUN_ERR_QUEUE_OVERFLOW, RUN_ERR_STACK_OVERFLOW, RUN_ERR_NUMERIC_OVERFLOW, - RUN_ERR_VALUE_OUT_OF_RANGE + RUN_ERR_VALUE_OUT_OF_RANGE, + RUN_ERR_GC_OVERFLOW }; extern const char *ERR_MSG[]; @@ -2,6 +2,7 @@ #include "builtin.h" #include "exc.h" #include "consts.h" +#include "gc.h" #include <cstdio> extern Pair *empty_list; @@ -91,6 +92,7 @@ void Evaluator::add_builtin_routines() { Evaluator::Evaluator() { envt = new Environment(NULL); // Top-level Environment + gc.attach(envt); add_builtin_routines(); } @@ -113,8 +115,7 @@ inline void push(Pair * &pc, FrameObj ** &top_ptr, Environment *envt) { // puts("oops"); if (pc->car->is_simple_obj()) // Not an opt invocation { - *top_ptr = envt->get_obj(pc->car); // Objectify the symbol - top_ptr++; + *top_ptr++ = gc.attach(envt->get_obj(pc->car)); // Objectify the symbol pc = pc->next; // Move to the next instruction // if (pc == empty_list) // puts("oops"); @@ -148,8 +149,12 @@ EvalObj *Evaluator::run_expr(Pair *prog) { FrameObj **top_ptr = eval_stack; Pair *pc = prog; Continuation *cont = NULL; +#ifdef GC_DEBUG + fprintf(stderr, "Start the evaluation...\n"); +#endif // envt is this->envt push(pc, top_ptr, envt); + gc.attach(prog); while((*eval_stack)->is_ret_addr()) { @@ -161,21 +166,34 @@ EvalObj *Evaluator::run_expr(Pair *prog) { { Pair *args = empty_list; while (!(*(--top_ptr))->is_ret_addr()) - args = new Pair(static_cast<EvalObj*>(*top_ptr), args); + { + EvalObj* obj = static_cast<EvalObj*>(*top_ptr); + gc.expose(obj); + args = new Pair(obj, args); + } //< static_cast because the while condition RetAddr *ret_addr = static_cast<RetAddr*>(*top_ptr); + gc.attach(args); if (!ret_addr->addr) { Pair *nexp = TO_PAIR(cont->proc_body->cdr); cont->proc_body = nexp; if (nexp == empty_list) { - *top_ptr = args->car; + *top_ptr = gc.attach(args->car); + + gc.expose(envt); envt = cont->envt; + gc.attach(envt); + pc = cont->pc->next; + + gc.expose(cont); cont = cont->prev_cont; + gc.attach(cont); } else pc = nexp; + gc.expose(args); top_ptr++; } else @@ -186,9 +204,11 @@ EvalObj *Evaluator::run_expr(Pair *prog) { call(args, envt, cont, top_ptr); else throw TokenError(opt->ext_repr(), SYN_ERR_CAN_NOT_APPLY); + gc.force(); } } } + gc.expose(prog); // static_cast because the previous while condition return static_cast<EvalObj*>(*(eval_stack)); } @@ -0,0 +1,113 @@ +#include "gc.h" +#include "exc.h" +#include "consts.h" + +#if defined(GC_DEBUG) || defined (GC_INFO) +#include <cstdio> +typedef unsigned long long ull; +#endif + +static EvalObj *gcq[GC_QUEUE_SIZE]; + +GarbageCollector::GarbageCollector() { + mapping.clear(); + pend_cnt = 0; + pending_list = NULL; +} + +GarbageCollector::PendingEntry::PendingEntry( + EvalObj *_obj, PendingEntry *_next) : obj(_obj), next(_next) {} + + +void GarbageCollector::expose(EvalObj *ptr) { + bool flag = mapping.count(ptr); + if (flag) + { +#ifdef GC_DEBUG + fprintf(stderr, "GC: 0x%llx exposed. count = %lu \"%s\"\n", + (ull)ptr, mapping[ptr] - 1, ptr->ext_repr().c_str()); +#endif + if (!--mapping[ptr]) + { +#ifdef GC_DEBUG + fprintf(stderr, "GC: 0x%llx pending. \n", (ull)ptr); +#endif + pending_list = new PendingEntry(ptr, pending_list); + } + } +} + +void GarbageCollector::force() { + EvalObj **l = gcq, **r = l; + for (PendingEntry *p = pending_list, *np; p; p = np) + { + np = p->next; + if (mapping[p->obj] == 0) + *r++ = p->obj; + delete p; + } // fetch the pending pointers in the list + // clear the list + pending_list = NULL; +/* for (EvalObj2Int::iterator it = mapping.begin(); + it != mapping.end(); it++) + if (it->second == 0) *r++ = it->first;*/ + +#ifdef GC_INFO + fprintf(stderr, "%ld\n", mapping.size()); + size_t cnt = 0; +#endif +#ifdef GC_DEBUG + fprintf(stderr, + "================================\n" + "GC: Forcing the clear process...\n"); +#endif + for (; l != r; l++) + { +#ifdef GC_DEBUG + fprintf(stderr, "GC: !!! destroying space 0x%llx. \n", (ull)*l); +#endif +#ifdef GC_INFO + cnt++; +#endif + delete *l; + mapping.erase(*l); + // maybe it's a complex structure, + // so that more pointers are reported + for (PendingEntry *p = pending_list, *np; p; p = np) + { + np = p->next; + *r++ = p->obj; + if (r == gcq + GC_QUEUE_SIZE) + throw NormalError(RUN_ERR_GC_OVERFLOW); + delete p; + } + pending_list = NULL; + } +#ifdef GC_INFO + fprintf(stderr, "GC: Forced clear, %lu objects are freed, " + "%lu remains\n" + "=============================\n", cnt, mapping.size()); + +#endif +#ifdef GC_DEBUG +/* for (EvalObj2Int::iterator it = mapping.begin(); + it != mapping.end(); it++) + fprintf(stderr, "%llx => %s\n", (ull)it->first, it->first->ext_repr().c_str()); + */ +#endif +} + +EvalObj *GarbageCollector::attach(EvalObj *ptr) { + if (!ptr) return NULL; // NULL pointer + bool flag = mapping.count(ptr); + if (flag) mapping[ptr]++; + else mapping[ptr] = 1; +#ifdef GC_DEBUG + fprintf(stderr, "GC: 0x%llx attached. count = %lu \"%s\"\n", + (ull)ptr, mapping[ptr], ptr->ext_repr().c_str()); +#endif + if (mapping.size() > GC_QUEUE_SIZE >> 1) + force(); + return ptr; // passing through +} + @@ -0,0 +1,32 @@ +#ifndef GC_H +#define GC_H + +#include "model.h" +#include <map> + +const int GC_QUEUE_SIZE = 262144; + +typedef std::map<EvalObj*, size_t> EvalObj2Int; + +class GarbageCollector { + + struct PendingEntry { + EvalObj *obj; + PendingEntry *next; + PendingEntry(EvalObj *obj, PendingEntry *next); + }; + + EvalObj2Int mapping; + size_t pend_cnt; + PendingEntry *pending_list; + + public: + GarbageCollector(); + void force(); + void expose(EvalObj *ptr); + EvalObj *attach(EvalObj *ptr); +}; + +extern GarbageCollector gc; + +#endif @@ -3,13 +3,15 @@ #include "parser.h" #include "eval.h" #include "exc.h" +#include "gc.h" #include <cstdio> #include <cstdlib> -Tokenizor *tk = new Tokenizor(); -ASTGenerator *ast = new ASTGenerator(); -Evaluator *eval = new Evaluator(); +GarbageCollector gc; +Tokenizor tk; +ASTGenerator ast; +Evaluator eval; void load_file(const char *fname) { FILE *f = fopen(fname, "r"); @@ -18,19 +20,21 @@ void load_file(const char *fname) { printf("Can not open file: %s\n", fname); exit(0); } - tk->set_stream(f); + tk.set_stream(f); while (1) { try { - Pair *tree = ast->absorb(tk); + Pair *tree = ast.absorb(&tk); if (!tree) break; - eval->run_expr(tree); + EvalObj *ret = eval.run_expr(tree); + gc.expose(ret); } catch (GeneralError &e) { fprintf(stderr, "An error occured: %s\n", e.get_msg().c_str()); } + gc.force(); } } @@ -46,8 +50,15 @@ void print_help(const char *cmd) { exit(0); } +EmptyList *empty_list = new EmptyList(); +UnspecObj *unspec_obj = new UnspecObj(); + int main(int argc, char **argv) { + //freopen("in.scm", "r", stdin); + gc.attach(empty_list); + gc.attach(unspec_obj); + for (int i = 1; i < argc; i++) { if (*argv[i] == '-') // parsing options @@ -79,20 +90,23 @@ int main(int argc, char **argv) { } int rcnt = 0; - tk->set_stream(stdin); // interactive mode + tk.set_stream(stdin); // interactive mode while (1) { fprintf(stderr, "Sonsi> "); try { - Pair *tree = ast->absorb(tk); + Pair *tree = ast.absorb(&tk); if (!tree) break; - string output = eval->run_expr(tree)->ext_repr(); + EvalObj *ret = eval.run_expr(tree); + string output = ret->ext_repr(); + gc.expose(ret); fprintf(stderr, "Ret> $%d = %s\n", rcnt++, output.c_str()); } catch (GeneralError &e) { fprintf(stderr, "An error occured: %s\n", e.get_msg().c_str()); } + gc.force(); } } @@ -5,6 +5,7 @@ #include "exc.h" #include "consts.h" #include "builtin.h" +#include "gc.h" using std::stringstream; diff --git a/test/q.scm b/test/q.scm new file mode 100644 index 0000000..498cfad --- /dev/null +++ b/test/q.scm @@ -0,0 +1,69 @@ +(define (shl bits) + (define len (vector-length bits)) + (define res (make-vector len)) + (define (copy i) + (if (= i (- len 1)) + #t + (and + (vector-set! res i + (vector-ref bits (+ i 1))) + (copy (+ i 1))))) + (copy 0) + (set! copy '()) + (vector-set! res (- len 1) #f) + res) + +(define (shr bits) + (define len (vector-length bits)) + (define res (make-vector len)) + (define (copy i) + (if (= i (- len 1)) + #t + (and + (vector-set! res (+ i 1) + (vector-ref bits i)) + (copy (+ i 1))))) + (copy 0) + (set! copy '()) + (vector-set! res 0 #f) + res) + +(define (empty-bits len) (make-vector len #f)) +(define vs vector-set!) +(define vr vector-ref) +(define res 0) +(define (queen n) + + (define (search l m r step) + (define (col-iter c) + (if (= c n) + #f + (and + (if (and (eq? (vr l c) #f) + (eq? (vr r c) #f) + (eq? (vr m c) #f)) + (and + (vs l c #t) + (vs m c #t) + (vs r c #t) + ((lambda () (search l m r (+ step 1)) #t)) + (vs l c #f) + (vs m c #f) + (vs r c #f)) + ) + (col-iter (+ c 1)) + ))) + (set! l (shl l)) + (set! r (shr r)) + (if (= step n) + (set! res (+ res 1)) + (col-iter 0))) + ; (set! col-iter '())) + + (search (empty-bits n) + (empty-bits n) + (empty-bits n) + 0) + res) + +(display (queen 8)) @@ -2,6 +2,7 @@ #include "model.h" #include "exc.h" #include "consts.h" +#include "gc.h" #include <cmath> #include <cstdlib> @@ -11,16 +12,24 @@ const double EPS = 1e-16; const int PREC = 16; -EmptyList *empty_list = new EmptyList(); -UnspecObj *unspec_obj = new UnspecObj(); +extern EmptyList *empty_list; +extern UnspecObj *unspec_obj; -Pair::Pair(EvalObj *_car, EvalObj *_cdr) : - EvalObj(CLS_PAIR_OBJ), car(_car), cdr(_cdr), - next(NULL) {} +Pair::Pair(EvalObj *_car, EvalObj *_cdr) : EvalObj(CLS_PAIR_OBJ), + car(_car), cdr(_cdr), next(NULL) { - ReprCons *Pair::get_repr_cons() { - return new PairReprCons(this, this); - } + gc.attach(car); + gc.attach(cdr); +} + +Pair::~Pair() { + gc.expose(car); + gc.expose(cdr); +} + +ReprCons *Pair::get_repr_cons() { + return new PairReprCons(this, this); +} ParseBracket::ParseBracket(unsigned char _btype) : @@ -41,41 +50,58 @@ SymObj::SymObj(const string &str) : OptObj::OptObj() : EvalObj(CLS_SIM_OBJ | CLS_OPT_OBJ) {} -ProcObj::ProcObj(Pair *_body, - Environment *_envt, - EvalObj *_params) : - OptObj(), body(_body), params(_params), envt(_envt) {} +ProcObj::ProcObj(Pair *_body, Environment *_envt, EvalObj *_params) : + OptObj(), body(_body), params(_params), envt(_envt) { + gc.attach(body); + gc.attach(params); + gc.attach(envt); +} + +ProcObj::~ProcObj() { + gc.expose(body); + gc.expose(params); + gc.expose(envt); +} + +Pair *ProcObj::call(Pair *_args, Environment * &genvt, + Continuation * &cont, FrameObj ** &top_ptr) { + // Create a new continuation + // static_cast see `call` invocation in eval.cpp + Pair *ret_addr = static_cast<RetAddr*>(*top_ptr)->addr; + Continuation *_cont = new Continuation(genvt, ret_addr, cont, body); + // Create local env and recall the closure + Environment *_envt = new Environment(envt); + // static_cast<SymObj*> because the params is already checked + EvalObj *ppar, *nptr; + Pair *args = _args; + for (ppar = params; + ppar->is_pair_obj(); + ppar = TO_PAIR(ppar)->cdr) + { + if ((nptr = args->cdr) != empty_list) + args = TO_PAIR(nptr); + else break; + _envt->add_binding(static_cast<SymObj*>(TO_PAIR(ppar)->car), args->car); + } - Pair *ProcObj::call(Pair *args, Environment * &genvt, - Continuation * &cont, FrameObj ** &top_ptr) { - // Create a new continuation - // static_cast see `call` invocation in eval.cpp - Pair *ret_addr = static_cast<RetAddr*>(*top_ptr)->addr; - Continuation *_cont = new Continuation(genvt, ret_addr, cont, body); - // Create local env and recall the closure - Environment *_envt = new Environment(envt); - // static_cast<SymObj*> because the params is already checked - EvalObj *ppar, *nptr; - for (ppar = params; - ppar->is_pair_obj(); - ppar = TO_PAIR(ppar)->cdr) - { - if ((nptr = args->cdr) != empty_list) - args = TO_PAIR(nptr); - else break; - _envt->add_binding(static_cast<SymObj*>(TO_PAIR(ppar)->car), args->car); - } + if (ppar->is_sym_obj()) + _envt->add_binding(static_cast<SymObj*>(ppar), args->cdr); // (... . var_n) + else if (args->cdr != empty_list || ppar != empty_list) + throw TokenError("", RUN_ERR_WRONG_NUM_OF_ARGS); - if (ppar->is_sym_obj()) - _envt->add_binding(static_cast<SymObj*>(ppar), args->cdr); // (... . var_n) - else if (args->cdr != empty_list || ppar != empty_list) - throw TokenError("", RUN_ERR_WRONG_NUM_OF_ARGS); + gc.expose(genvt); + genvt = _envt; + gc.attach(genvt); - genvt = _envt; - cont = _cont; - *top_ptr++ = new RetAddr(NULL); // Mark the entrance of a cont - return body; // Move pc to the proc entry point - } + gc.expose(cont); + cont = _cont; + gc.attach(cont); + + delete *top_ptr; // release ret addr + *top_ptr++ = new RetAddr(NULL); // Mark the entrance of a cont + gc.expose(_args); + return body; // Move pc to the proc entry point +} ReprCons *ProcObj::get_repr_cons() { return new ReprStr("#<Procedure>"); @@ -204,7 +230,9 @@ BuiltinProcObj::BuiltinProcObj(BuiltinProc f, string _name) : Continuation * &cont, FrameObj ** &top_ptr) { Pair *ret_addr = static_cast<RetAddr*>(*top_ptr)->addr; - *top_ptr++ = handler(TO_PAIR(args->cdr), name); + delete *top_ptr; + *top_ptr++ = gc.attach(handler(TO_PAIR(args->cdr), name)); + gc.expose(args); return ret_addr->next; // Move to the next instruction } @@ -212,7 +240,20 @@ ReprCons *BuiltinProcObj::get_repr_cons() { return new ReprStr("#<Builtin Procedure: " + name + ">"); } -Environment::Environment(Environment *_prev_envt) : prev_envt(_prev_envt) {} +Environment::Environment(Environment *_prev_envt) : prev_envt(_prev_envt) { + gc.attach(prev_envt); +} + +Environment::~Environment() { + for (Str2EvalObj::iterator it = binding.begin(); + it != binding.end(); it++) + gc.expose(it->second); + gc.expose(prev_envt); +} + +ReprCons *Environment::get_repr_cons() { + return new ReprStr("#<Environment>"); +} bool Environment::add_binding(SymObj *sym_obj, EvalObj *eval_obj, bool def) { bool found = false; @@ -224,7 +265,10 @@ bool Environment::add_binding(SymObj *sym_obj, EvalObj *eval_obj, bool def) { bool has_key = ptr->binding.count(name); if (has_key) { - ptr->binding[name] = eval_obj; + EvalObj * &ref = ptr->binding[name]; + gc.expose(ref); + ref = eval_obj; + gc.attach(ref); found = true; break; } @@ -233,7 +277,18 @@ bool Environment::add_binding(SymObj *sym_obj, EvalObj *eval_obj, bool def) { } else { - binding[name] = eval_obj; + if (!binding.count(name)) + { + binding[name] = eval_obj; + gc.attach(eval_obj); + } + else + { + EvalObj * &ref = binding[name]; + gc.expose(ref); + ref = eval_obj; + gc.attach(ref); + } return true; } } @@ -253,17 +308,27 @@ EvalObj *Environment::get_obj(EvalObj *obj) { } Continuation::Continuation(Environment *_envt, Pair *_pc, - Continuation *_prev_cont, - Pair *_proc_body) : - prev_cont(_prev_cont), envt(_envt), pc(_pc), - proc_body(_proc_body) {} - - ReprCons::ReprCons(bool _done, EvalObj *_ori) : ori(_ori), done(_done) {} - ReprStr::ReprStr(string _repr) : ReprCons(true) { repr = _repr; } - EvalObj *ReprStr::next(const string &prev) { - throw NormalError(INT_ERR); + Continuation *_prev_cont, Pair *_proc_body) : + prev_cont(_prev_cont), envt(_envt), pc(_pc), proc_body(_proc_body) { + gc.attach(prev_cont); + gc.attach(envt); } +Continuation::~Continuation() { + gc.expose(prev_cont); + gc.expose(envt); +} + +ReprCons *Continuation::get_repr_cons() { + return new ReprStr("#<Continuation>"); +} + +ReprCons::ReprCons(bool _done, EvalObj *_ori) : ori(_ori), done(_done) {} +ReprStr::ReprStr(string _repr) : ReprCons(true) { repr = _repr; } +EvalObj *ReprStr::next(const string &prev) { + throw NormalError(INT_ERR); +} + PairReprCons::PairReprCons(Pair *_ptr, EvalObj *_ori) : ReprCons(false, _ori), state(0), ptr(_ptr) {} @@ -324,8 +389,8 @@ VectReprCons::VectReprCons(VecObj *_ptr, EvalObj *_ori) : PromObj::PromObj(EvalObj *exp) : EvalObj(CLS_SIM_OBJ | CLS_PROM_OBJ), entry(new Pair(exp, empty_list)), mem(NULL) { - entry->next = NULL; -} + entry->next = NULL; + } Pair *PromObj::get_entry() { return entry; } @@ -421,13 +486,13 @@ CompNumObj::CompNumObj(double _real, double _imag) : #ifndef GMP_SUPPORT real = int_ptr->val; #else - real = int_ptr->val.get_d(); + real = int_ptr->val.get_d(); #endif else if ((rat_ptr = RatNumObj::from_string(real_str))) #ifndef GMP_SUPPORT real = rat_ptr->a / double(rat_ptr->b); #else - real = rat_ptr->val.get_d(); + real = rat_ptr->val.get_d(); #endif else if ((real_ptr = RealNumObj::from_string(real_str))) real = real_ptr->real; @@ -440,13 +505,13 @@ CompNumObj::CompNumObj(double _real, double _imag) : #ifndef GMP_SUPPORT imag = int_ptr->val; #else - imag = int_ptr->val.get_d(); + imag = int_ptr->val.get_d(); #endif else if ((rat_ptr = RatNumObj::from_string(imag_str))) #ifndef GMP_SUPPORT imag = rat_ptr->a / double(rat_ptr->b); #else - imag = rat_ptr->val.get_d(); + imag = rat_ptr->val.get_d(); #endif else if ((real_ptr = RealNumObj::from_string(imag_str))) imag = real_ptr->real; @@ -456,11 +521,16 @@ CompNumObj::CompNumObj(double _real, double _imag) : return new CompNumObj(real, imag); } +NumObj *CompNumObj::clone() const { + return new CompNumObj(*this); +} + CompNumObj *CompNumObj::convert(NumObj *obj) { switch (obj->level) { case NUM_LVL_COMP : - return static_cast<CompNumObj*>(obj); break; + return new CompNumObj(*static_cast<CompNumObj*>(obj)); + break; case NUM_LVL_REAL : return new CompNumObj(static_cast<RealNumObj*>(obj)->real, 0); break; @@ -489,30 +559,32 @@ CompNumObj *CompNumObj::convert(NumObj *obj) { #define C (r->real) #define D (r->imag) -NumObj *CompNumObj::add(NumObj *_r) { +void CompNumObj::add(NumObj *_r) { CompNumObj *r = static_cast<CompNumObj*>(_r); - return new CompNumObj(A + C, B + D); + real += C; + imag += D; } -NumObj *CompNumObj::sub(NumObj *_r) { +void CompNumObj::sub(NumObj *_r) { CompNumObj *r = static_cast<CompNumObj*>(_r); - return new CompNumObj(A - C, B - D); + real -= C; + imag -= D; } -NumObj *CompNumObj::mul(NumObj *_r) { +void CompNumObj::mul(NumObj *_r) { CompNumObj *r = static_cast<CompNumObj*>(_r); - return new CompNumObj(A * C - B * D, - B * C + A * D); + A = A * C - B * D; + B = B * C + A * D; } -NumObj *CompNumObj::div(NumObj *_r) { +void CompNumObj::div(NumObj *_r) { CompNumObj *r = static_cast<CompNumObj*>(_r); double f = C * C + D * D; if (f == 0) throw NormalError(RUN_ERR_NUMERIC_OVERFLOW); f = 1 / f; - return new CompNumObj((A * C + B * D) * f, - (B * C - A * D) * f); + A = (A * C + B * D) * f, + B = (B * C - A * D) * f; } bool NumObj::lt(NumObj *_r) { @@ -531,7 +603,7 @@ bool NumObj::ge(NumObj *_r) { throw TokenError("a comparable number", RUN_ERR_WRONG_TYPE); } -NumObj *NumObj::abs() { +void NumObj::abs() { throw TokenError("a real number", RUN_ERR_WRONG_TYPE); } @@ -553,6 +625,10 @@ ReprCons *CompNumObj::get_repr_cons() { RealNumObj::RealNumObj(double _real) : InexactNumObj(NUM_LVL_REAL), real(_real) {} +NumObj *RealNumObj::clone() const { + return new RealNumObj(*this); +} + RealNumObj *RealNumObj::from_string(string repr) { bool flag; double real = str_to_double(repr, flag); @@ -564,7 +640,8 @@ RealNumObj *RealNumObj::convert(NumObj *obj) { switch (obj->level) { case NUM_LVL_REAL: - return static_cast<RealNumObj*>(obj); break; + return new RealNumObj(*static_cast<RealNumObj*>(obj)); + break; case NUM_LVL_RAT: { RatNumObj *rat = static_cast<RatNumObj*>(obj); @@ -586,24 +663,24 @@ RealNumObj *RealNumObj::convert(NumObj *obj) { throw NormalError(INT_ERR); } -NumObj *RealNumObj::add(NumObj *_r) { - return new RealNumObj(real + static_cast<RealNumObj*>(_r)->real); +void RealNumObj::add(NumObj *_r) { + real += static_cast<RealNumObj*>(_r)->real; } -NumObj *RealNumObj::sub(NumObj *_r) { - return new RealNumObj(real - static_cast<RealNumObj*>(_r)->real); +void RealNumObj::sub(NumObj *_r) { + real -= static_cast<RealNumObj*>(_r)->real; } -NumObj *RealNumObj::mul(NumObj *_r) { - return new RealNumObj(real * static_cast<RealNumObj*>(_r)->real); +void RealNumObj::mul(NumObj *_r) { + real *= static_cast<RealNumObj*>(_r)->real; } -NumObj *RealNumObj::div(NumObj *_r) { - return new RealNumObj(real / static_cast<RealNumObj*>(_r)->real); +void RealNumObj::div(NumObj *_r) { + real /= static_cast<RealNumObj*>(_r)->real; } -NumObj *RealNumObj::abs() { - return new RealNumObj(fabs(real)); +void RealNumObj::abs() { + real = fabs(real); } bool RealNumObj::eq(NumObj *_r) { @@ -659,9 +736,12 @@ RatNumObj *RatNumObj::from_string(string repr) { return new RatNumObj(a, b); } #else -RatNumObj::RatNumObj(mpq_class _val) : - ExactNumObj(NUM_LVL_RAT), val(_val) { - val.canonicalize(); +RatNumObj::RatNumObj(mpq_class _val) : ExactNumObj(NUM_LVL_RAT), val(_val) { + val.canonicalize(); +} + +NumObj *RatNumObj::clone() const { + return new RatNumObj(*this); } RatNumObj *RatNumObj::from_string(string repr) { @@ -678,6 +758,9 @@ RatNumObj *RatNumObj::from_string(string repr) { return NULL; } } + +RatNumObj::RatNumObj(const RatNumObj &ori) : + ExactNumObj(NUM_LVL_RAT), val(ori.val.get_mpq_t()) {} #endif @@ -685,7 +768,8 @@ RatNumObj *RatNumObj::convert(NumObj *obj) { switch (obj->level) { case NUM_LVL_RAT: - return static_cast<RatNumObj*>(obj); break; + return new RatNumObj(*static_cast<RatNumObj*>(obj)); + break; case NUM_LVL_INT: #ifndef GMP_SUPPORT return new RatNumObj(static_cast<IntNumObj*>(obj)->val, 1); @@ -703,55 +787,57 @@ RatNumObj *RatNumObj::convert(NumObj *obj) { #define C (r->a) #define D (r->b) -NumObj *RatNumObj::add(NumObj *_r) { +void RatNumObj::add(NumObj *_r) { RatNumObj *r = static_cast<RatNumObj*>(_r); #ifndef GMP_SUPPORT - int na = A * D + B * C, nb = B * D; + A = A * D + B * C; + B = B * D; int g = gcd(na, nb); - na /= g; - nb /= g; - return new RatNumObj(na, nb); + A /= g; + B /= g; #else - return new RatNumObj(val + r->val); + val += r->val; #endif } -NumObj *RatNumObj::sub(NumObj *_r) { +void RatNumObj::sub(NumObj *_r) { RatNumObj *r = static_cast<RatNumObj*>(_r); #ifndef GMP_SUPPORT - int na = A * D - B * C, nb = B * D; + A = A * D - B * C; + B = B * D; int g = gcd(na, nb); - na /= g; - nb /= g; - return new RatNumObj(na, nb); + A /= g; + B /= g; #else - return new RatNumObj(val - r->val); + val -= r->val; #endif } -NumObj *RatNumObj::mul(NumObj *_r) { +void RatNumObj::mul(NumObj *_r) { RatNumObj *r = static_cast<RatNumObj*>(_r); #ifndef GMP_SUPPORT - int na = A * C, nb = B * D; + A = A * C; + B = B * D; int g = gcd(na, nb); - na /= g; - nb /= g; - return new RatNumObj(na, nb); + A /= g; + B /= g; #else - return new RatNumObj(val * r->val); + val *= r->val; #endif } -NumObj *RatNumObj::div(NumObj *_r) { +void RatNumObj::div(NumObj *_r) { RatNumObj *r = static_cast<RatNumObj*>(_r); #ifndef GMP_SUPPORT - int na = A * D, nb = B * C; + A = A * D; + B = B * C; int g = gcd(na, nb); - na /= g; - nb /= g; - return new RatNumObj(na, nb); + A /= g; + B /= g; #else - return new RatNumObj(val / r->val); + if (r->val == 0) + throw NormalError(RUN_ERR_NUMERIC_OVERFLOW); + val /= r->val; #endif } @@ -801,11 +887,11 @@ bool RatNumObj::eq(NumObj *_r) { #endif } -NumObj *RatNumObj::abs() { +void RatNumObj::abs() { #ifndef GMP_SUPPORT - return new RatNumObj((a > 0 ? a : -a), b); + if (a < 0) a = -a; #else - return new RatNumObj(::abs(val)); + val = ::abs(val); #endif } @@ -820,6 +906,7 @@ ReprCons *RatNumObj::get_repr_cons() { #ifndef GMP_SUPPORT IntNumObj::IntNumObj(int _val) : ExactNumObj(NUM_LVL_INT), val(_val) {} + IntNumObj *IntNumObj::from_string(string repr) { int val = 0; for (size_t i = 0; i < repr.length(); i++) @@ -845,75 +932,71 @@ IntNumObj *IntNumObj::from_string(string repr) { } } int IntNumObj::get_i() { return val.get_si(); } +IntNumObj::IntNumObj(const IntNumObj &ori) : + ExactNumObj(NUM_LVL_INT), val(ori.val.get_mpz_t()) {} #endif + +NumObj *IntNumObj::clone() const { + return new IntNumObj(*this); +} + IntNumObj *IntNumObj::convert(NumObj *obj) { switch (obj->level) { case NUM_LVL_INT : - return static_cast<IntNumObj*>(obj); + return new IntNumObj(*static_cast<IntNumObj*>(obj)); default: throw NormalError(INT_ERR); } } -NumObj *IntNumObj::add(NumObj *_r) { - return new IntNumObj(val + static_cast<IntNumObj*>(_r)->val); -} - -NumObj *IntNumObj::sub(NumObj *_r) { - return new IntNumObj(val - static_cast<IntNumObj*>(_r)->val); +void IntNumObj::add(NumObj *_r) { + val += static_cast<IntNumObj*>(_r)->val; } -NumObj *IntNumObj::mul(NumObj *_r) { - return new IntNumObj(val * static_cast<IntNumObj*>(_r)->val); +void IntNumObj::sub(NumObj *_r) { + val -= static_cast<IntNumObj*>(_r)->val; } -NumObj *IntNumObj::div(NumObj *_r) { -#ifndef GMP_SUPPORT - return new RatNumObj(val, static_cast<IntNumObj*>(_r)->val); -#else - mpz_class d(static_cast<IntNumObj*>(_r)->val); - if (d == 0) throw NormalError(RUN_ERR_NUMERIC_OVERFLOW); - return new RatNumObj(mpq_class(val, d)); -#endif +void IntNumObj::mul(NumObj *_r) { + val *= static_cast<IntNumObj*>(_r)->val; } -NumObj *IntNumObj::abs() { - return new IntNumObj(::abs(val)); +void IntNumObj::abs() { + val = ::abs(val); } -NumObj *IntNumObj::rem(NumObj *_r) { +void IntNumObj::rem(NumObj *_r) { const mpz_class &rval(static_cast<IntNumObj*>(_r)->val); if (rval == 0) throw NormalError(RUN_ERR_NUMERIC_OVERFLOW); - return new IntNumObj(val % rval); + val %= rval; } -NumObj *IntNumObj::mod(NumObj *_r) { +void IntNumObj::mod(NumObj *_r) { const mpz_class &rval = static_cast<IntNumObj*>(_r)->val; if (rval == 0) throw NormalError(RUN_ERR_NUMERIC_OVERFLOW); - mpz_class ret = val % rval; - if (ret != 0 && sgn(ret) != sgn(rval)) - ret = ret + rval; - return new IntNumObj(ret); + val %= rval; + if (val != 0 && sgn(val) != sgn(rval)) + val += rval; } -NumObj *IntNumObj::quo(NumObj *_r) { +void IntNumObj::div(NumObj *_r) { const mpz_class &rval = static_cast<IntNumObj*>(_r)->val; if (rval == 0) throw NormalError(RUN_ERR_NUMERIC_OVERFLOW); - return new IntNumObj(val / rval); + val /= rval; } -NumObj *IntNumObj::gcd(NumObj *_r) { +void IntNumObj::gcd(NumObj *_r) { mpz_t g; mpz_gcd(g, val.get_mpz_t(), static_cast<IntNumObj*>(_r)->val.get_mpz_t()); - return new IntNumObj(mpz_class(g)); + val = mpz_class(g); } -NumObj *IntNumObj::lcm(NumObj *_r) { +void IntNumObj::lcm(NumObj *_r) { mpz_t l; mpz_lcm(l, val.get_mpz_t(), static_cast<IntNumObj*>(_r)->val.get_mpz_t()); - return new IntNumObj(mpz_class(l)); + val = mpz_class(l); } bool IntNumObj::lt(NumObj *_r) { @@ -25,6 +25,9 @@ const int CLS_CHAR_OBJ = 1 << 6; const int CLS_STR_OBJ = 1 << 7; const int CLS_VECT_OBJ = 1 << 8; +const int CLS_CONT_OBJ = 1 << 9; +const int CLS_ENVT_OBJ = 1 << 10; + static const int NUM_LVL_COMP = 0; static const int NUM_LVL_REAL = 1; static const int NUM_LVL_RAT = 2; @@ -48,6 +51,7 @@ class Pair : public EvalObj {/*{{{*/ Pair* next; /**< The next branch in effect */ Pair(EvalObj *car, EvalObj *cdr); /**< Create a Pair (car . cdr) */ + ~Pair(); ReprCons *get_repr_cons(); };/*}}}*/ @@ -160,6 +164,7 @@ class ProcObj: public OptObj {/*{{{*/ /** Conctructs a ProcObj */ ProcObj(Pair *body, Environment *envt, EvalObj *params); + ~ProcObj(); Pair *call(Pair *args, Environment * &envt, Continuation * &cont, FrameObj ** &top_ptr); ReprCons *get_repr_cons(); @@ -229,13 +234,14 @@ class NumObj: public EvalObj {/*{{{*/ * Construct a general Numeric object */ NumObj(NumLvl level, bool _exactness); + virtual NumObj *clone() const = 0; bool is_exact(); virtual NumObj *convert(NumObj *r) = 0; - virtual NumObj *add(NumObj *r) = 0; - virtual NumObj *sub(NumObj *r) = 0; - virtual NumObj *mul(NumObj *r) = 0; - virtual NumObj *div(NumObj *r) = 0; - virtual NumObj *abs(); + virtual void add(NumObj *r) = 0; + virtual void sub(NumObj *r) = 0; + virtual void mul(NumObj *r) = 0; + virtual void div(NumObj *r) = 0; + virtual void abs(); virtual bool lt(NumObj *r); virtual bool gt(NumObj *r); @@ -323,7 +329,7 @@ class PromObj: public EvalObj {/*{{{*/ /** @class Environment * The environment of current evaluation, i.e. the local variable binding */ -class Environment {/*{{{*/ +class Environment : public EvalObj{/*{{{*/ private: Environment *prev_envt; /**< Pointer to the upper-level environment */ Str2EvalObj binding; /**< Store all pairs of identifier and its @@ -333,6 +339,7 @@ class Environment {/*{{{*/ * @param prev_envt the outer environment */ Environment(Environment *prev_envt); + ~Environment(); /** Add a binding entry which binds sym_obj to eval_obj * @param def true to force the assignment * @return when def is set to false, this return value is true iff. the @@ -344,6 +351,7 @@ class Environment {/*{{{*/ * @param obj the object as request * */ EvalObj *get_obj(EvalObj *obj); + ReprCons *get_repr_cons(); };/*}}}*/ /** @class Continuation @@ -351,7 +359,7 @@ class Environment {/*{{{*/ * being made (Behave like a stack frame in C). When the call has accomplished, * the system will restore all the registers according to the continuation. */ -class Continuation {/*{{{*/ +class Continuation : public EvalObj {/*{{{*/ public: /** Linking the previous continuation on the chain */ Continuation *prev_cont; @@ -365,6 +373,8 @@ class Continuation {/*{{{*/ /** Create a continuation */ Continuation(Environment *envt, Pair *pc, Continuation *prev_cont, Pair *proc_body); + ~Continuation(); + ReprCons *get_repr_cons(); };/*}}}*/ /** @class InexactNumObj @@ -384,6 +394,7 @@ class CompNumObj: public InexactNumObj {/*{{{*/ /** Construct a complex number */ CompNumObj(double _real, double _imag); + NumObj *clone() const; /** Try to construct an CompNumObj object * @return NULL if failed */ @@ -391,10 +402,10 @@ class CompNumObj: public InexactNumObj {/*{{{*/ /** Convert to a complex number from other numeric types */ CompNumObj *convert(NumObj* obj); - NumObj *add(NumObj *r); - NumObj *sub(NumObj *r); - NumObj *mul(NumObj *r); - NumObj *div(NumObj *r); + void add(NumObj *r); + void sub(NumObj *r); + void mul(NumObj *r); + void div(NumObj *r); bool eq(NumObj *r); ReprCons *get_repr_cons(); };/*}}}*/ @@ -407,6 +418,7 @@ class RealNumObj: public InexactNumObj {/*{{{*/ double real; /** Construct a real number */ RealNumObj(double _real); + NumObj *clone() const; /** Try to construct an RealNumObj object * @return NULL if failed */ @@ -414,11 +426,11 @@ class RealNumObj: public InexactNumObj {/*{{{*/ /** Convert to a real number from other numeric types */ RealNumObj *convert(NumObj* obj); - NumObj *add(NumObj *r); - NumObj *sub(NumObj *r); - NumObj *mul(NumObj *r); - NumObj *div(NumObj *r); - NumObj *abs(); + void add(NumObj *r); + void sub(NumObj *r); + void mul(NumObj *r); + void div(NumObj *r); + void abs(); bool lt(NumObj *r); bool gt(NumObj *r); bool le(NumObj *r); @@ -449,7 +461,9 @@ class RatNumObj: public ExactNumObj {/*{{{*/ #else mpq_class val; RatNumObj(mpq_class val); + RatNumObj(const RatNumObj &ori); #endif + NumObj *clone() const; /** Try to construct an RatNumObj object * @return NULL if failed */ @@ -457,11 +471,11 @@ class RatNumObj: public ExactNumObj {/*{{{*/ /** Convert to a Rational number from other numeric types */ RatNumObj *convert(NumObj* obj); - NumObj *add(NumObj *r); - NumObj *sub(NumObj *r); - NumObj *mul(NumObj *r); - NumObj *div(NumObj *r); - NumObj *abs(); + void add(NumObj *r); + void sub(NumObj *r); + void mul(NumObj *r); + void div(NumObj *r); + void abs(); bool lt(NumObj *r); bool gt(NumObj *r); bool le(NumObj *r); @@ -485,7 +499,10 @@ class IntNumObj: public ExactNumObj {/*{{{*/ /** Construct a integer */ IntNumObj(mpz_class val); int get_i(); + /** Copy constructor */ + IntNumObj(const IntNumObj &ori); #endif + NumObj *clone() const; /** Try to construct an IntNumObj object * @return NULL if failed */ @@ -493,16 +510,17 @@ class IntNumObj: public ExactNumObj {/*{{{*/ /** Convert to a integer from other numeric types */ IntNumObj *convert(NumObj* obj); - NumObj *add(NumObj *r); - NumObj *sub(NumObj *r); - NumObj *mul(NumObj *r); - NumObj *div(NumObj *r); - NumObj *abs(); - NumObj *mod(NumObj *r); - NumObj *rem(NumObj *r); - NumObj *quo(NumObj *r); - NumObj *gcd(NumObj *r); - NumObj *lcm(NumObj *r); + void add(NumObj *r); + void sub(NumObj *r); + void mul(NumObj *r); + void div(NumObj *r); + void abs(); + void mod(NumObj *r); + void rem(NumObj *r); + void quo(NumObj *r); + void gcd(NumObj *r); + void lcm(NumObj *r); + bool lt(NumObj *r); bool gt(NumObj *r); bool le(NumObj *r); |