aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile7
-rw-r--r--builtin.cpp334
-rw-r--r--consts.cpp3
-rw-r--r--consts.h3
-rw-r--r--eval.cpp28
-rw-r--r--gc.cpp113
-rw-r--r--gc.h32
-rw-r--r--main.cpp32
-rw-r--r--parser.cpp1
-rw-r--r--test/q.scm69
-rw-r--r--types.cpp373
-rw-r--r--types.h80
12 files changed, 794 insertions, 281 deletions
diff --git a/Makefile b/Makefile
index aeab6a0..37142aa 100644
--- a/Makefile
+++ b/Makefile
@@ -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;
}
diff --git a/consts.cpp b/consts.cpp
index a04d5c7..fd835a4 100644
--- a/consts.cpp
+++ b/consts.cpp
@@ -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!"
};
diff --git a/consts.h b/consts.h
index b24e951..10cd951 100644
--- a/consts.h
+++ b/consts.h
@@ -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[];
diff --git a/eval.cpp b/eval.cpp
index 2f5921d..bf61b3e 100644
--- a/eval.cpp
+++ b/eval.cpp
@@ -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));
}
diff --git a/gc.cpp b/gc.cpp
new file mode 100644
index 0000000..13dfb3c
--- /dev/null
+++ b/gc.cpp
@@ -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
+}
+
diff --git a/gc.h b/gc.h
new file mode 100644
index 0000000..e807048
--- /dev/null
+++ b/gc.h
@@ -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
diff --git a/main.cpp b/main.cpp
index 78515a6..15a877e 100644
--- a/main.cpp
+++ b/main.cpp
@@ -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();
}
}
diff --git a/parser.cpp b/parser.cpp
index 333311e..6abc1c0 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -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))
diff --git a/types.cpp b/types.cpp
index ead14b8..6a24239 100644
--- a/types.cpp
+++ b/types.cpp
@@ -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) {
diff --git a/types.h b/types.h
index 11776ab..5147e2d 100644
--- a/types.h
+++ b/types.h
@@ -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);