diff options
-rw-r--r-- | TODO.rst | 3 | ||||
-rw-r--r-- | builtin.cpp | 136 | ||||
-rw-r--r-- | builtin.h | 45 | ||||
-rw-r--r-- | eval.cpp | 51 | ||||
-rw-r--r-- | model.cpp | 8 | ||||
-rw-r--r-- | model.h | 5 |
6 files changed, 169 insertions, 79 deletions
@@ -1,4 +1,3 @@ -- More sophisticated parser - GMP -- Quotation +- Pair literal parsing - Add macro support diff --git a/builtin.cpp b/builtin.cpp index a0b3830..9d25644 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -623,41 +623,47 @@ Cons *SpecialOptQuote::call(ArgList *args, Environment * &envt, string SpecialOptQuote::ext_repr() { return string("#<Builtin Macro: quote>"); } - -EvalObj *builtin_cons(ArgList *args) { - if (args == empty_list || - args->cdr == empty_list || - TO_CONS(args->cdr)->cdr != empty_list) - throw TokenError("cons", RUN_ERR_WRONG_NUM_OF_ARGS); - +#define ARGS_EXACTLY_TWO \ + if (args == empty_list || \ + args->cdr == empty_list || \ + TO_CONS(args->cdr)->cdr != empty_list) \ + throw TokenError(name, RUN_ERR_WRONG_NUM_OF_ARGS) + +#define ARGS_EXACTLY_ONE \ + if (args == empty_list || \ + args->cdr != empty_list) \ + throw TokenError(name, RUN_ERR_WRONG_NUM_OF_ARGS) + +#define ARGS_AT_LEAST_ONE \ + if (args == empty_list) \ + throw TokenError(name, RUN_ERR_WRONG_NUM_OF_ARGS) + +BUILTIN_PROC_DEF(make_pair) { + ARGS_EXACTLY_TWO; return new Cons(args->car, TO_CONS(args->cdr)->car); } -EvalObj *builtin_car(ArgList *args) { - if (args == empty_list || - args->cdr != empty_list) - throw TokenError("car", RUN_ERR_WRONG_NUM_OF_ARGS); +BUILTIN_PROC_DEF(pair_car) { + ARGS_EXACTLY_ONE; if (args->car == empty_list || !args->car->is_cons_obj()) - throw TokenError("pair", RUN_ERR_WRONG_TYPE); + throw TokenError(name, RUN_ERR_WRONG_TYPE); return TO_CONS(args->car)->car; } -EvalObj *builtin_cdr(ArgList *args) { - if (args == empty_list || - args->cdr != empty_list) - throw TokenError("cdr", RUN_ERR_WRONG_NUM_OF_ARGS); +BUILTIN_PROC_DEF(pair_cdr) { + ARGS_EXACTLY_ONE; if (args->car == empty_list || !args->car->is_cons_obj()) - throw TokenError("pair", RUN_ERR_WRONG_TYPE); + throw TokenError(name, RUN_ERR_WRONG_TYPE); return TO_CONS(args->car)->cdr; } -EvalObj *builtin_list(ArgList *args) { +BUILTIN_PROC_DEF(make_list) { return args; } -EvalObj *builtin_plus(ArgList *args) { +BUILTIN_PROC_DEF(num_add) { NumObj *res = new IntNumObj(0), *opr; // the most accurate type for (Cons *ptr = args; ptr != empty_list; ptr = TO_CONS(ptr->cdr)) { @@ -674,9 +680,9 @@ EvalObj *builtin_plus(ArgList *args) { return res; } -EvalObj *builtin_minus(ArgList *args) { +BUILTIN_PROC_DEF(num_sub) { if (args == empty_list) - throw TokenError("-", RUN_ERR_WRONG_NUM_OF_ARGS); + throw TokenError(name, RUN_ERR_WRONG_NUM_OF_ARGS); if (!args->car->is_num_obj()) throw TokenError("a number", RUN_ERR_WRONG_TYPE); @@ -698,7 +704,7 @@ EvalObj *builtin_minus(ArgList *args) { return res; } -EvalObj *builtin_multi(ArgList *args) { +BUILTIN_PROC_DEF(num_multi) { NumObj *res = new IntNumObj(1), *opr; // the most accurate type for (Cons *ptr = args; ptr != empty_list; ptr = TO_CONS(ptr->cdr)) { @@ -715,9 +721,9 @@ EvalObj *builtin_multi(ArgList *args) { return res; } -EvalObj *builtin_div(ArgList *args) { +BUILTIN_PROC_DEF(num_div) { if (args == empty_list) - throw TokenError("/", RUN_ERR_WRONG_NUM_OF_ARGS); + throw TokenError(name, RUN_ERR_WRONG_NUM_OF_ARGS); if (!args->car->is_num_obj()) throw TokenError("a number", RUN_ERR_WRONG_TYPE); @@ -739,9 +745,8 @@ EvalObj *builtin_div(ArgList *args) { return res; } -EvalObj *builtin_lt(ArgList *args) { - if (args == empty_list) - throw TokenError("<", RUN_ERR_WRONG_NUM_OF_ARGS); +BUILTIN_PROC_DEF(num_lt) { + ARGS_AT_LEAST_ONE; if (!args->car->is_num_obj()) throw TokenError("a number", RUN_ERR_WRONG_TYPE); @@ -764,9 +769,8 @@ EvalObj *builtin_lt(ArgList *args) { return new BoolObj(true); } -EvalObj *builtin_gt(ArgList *args) { - if (args == empty_list) - throw TokenError(">", RUN_ERR_WRONG_NUM_OF_ARGS); +BUILTIN_PROC_DEF(num_gt) { + ARGS_AT_LEAST_ONE; if (!args->car->is_num_obj()) throw TokenError("a number", RUN_ERR_WRONG_TYPE); @@ -789,9 +793,8 @@ EvalObj *builtin_gt(ArgList *args) { return new BoolObj(true); } -EvalObj *builtin_arithmetic_eq(ArgList *args) { - if (args == empty_list) - throw TokenError("=", RUN_ERR_WRONG_NUM_OF_ARGS); +BUILTIN_PROC_DEF(num_eq) { + ARGS_AT_LEAST_ONE; if (!args->car->is_num_obj()) throw TokenError("a number", RUN_ERR_WRONG_TYPE); @@ -814,24 +817,73 @@ EvalObj *builtin_arithmetic_eq(ArgList *args) { return new BoolObj(true); } +BUILTIN_PROC_DEF(bool_not) { + ARGS_EXACTLY_ONE; + return new BoolObj(!args->car->is_true()); +} + +BUILTIN_PROC_DEF(is_boolean) { + ARGS_EXACTLY_ONE; + return new BoolObj(args->car->is_bool_obj()); +} -EvalObj *builtin_exact(ArgList *args) { - if (args == empty_list || - args->cdr != empty_list) - throw TokenError("(in)exact?", RUN_ERR_WRONG_NUM_OF_ARGS); +BUILTIN_PROC_DEF(is_pair) { + ARGS_EXACTLY_ONE; + return new BoolObj(args->car->is_cons_obj()); +} + +BUILTIN_PROC_DEF(pair_set_car) { + ARGS_EXACTLY_TWO; + if (args->car == empty_list || !args->car->is_cons_obj()) + throw TokenError(name, RUN_ERR_WRONG_TYPE); + TO_CONS(args->car)->car = TO_CONS(args->cdr)->car; + return new UnspecObj(); +} + +BUILTIN_PROC_DEF(pair_set_cdr) { + ARGS_EXACTLY_TWO; + if (args->car == empty_list || !args->car->is_cons_obj()) + throw TokenError(name, RUN_ERR_WRONG_TYPE); + TO_CONS(args->car)->cdr = TO_CONS(args->cdr)->car; + return new UnspecObj(); +} + +BUILTIN_PROC_DEF(is_null) { + ARGS_EXACTLY_ONE; + return new BoolObj(args->car == empty_list); +} + +BUILTIN_PROC_DEF(is_list) { + ARGS_EXACTLY_ONE; + if (!args->car->is_cons_obj()) + return new BoolObj(false); + for (Cons *ptr = TO_CONS(args->car); ptr != empty_list;) + { + EvalObj *cdr = ptr->cdr; + if (!cdr->is_cons_obj()) + return new BoolObj(false); + else + ptr = TO_CONS(cdr); + } + return new BoolObj(true); +} + +BUILTIN_PROC_DEF(num_exact) { + ARGS_EXACTLY_ONE; if (!args->car->is_num_obj()) throw TokenError("a number", RUN_ERR_WRONG_TYPE); return new BoolObj(static_cast<NumObj*>(args->car)->is_exact()); } -EvalObj *builtin_inexact(ArgList *args) { - BoolObj *ret = static_cast<BoolObj*>(builtin_exact(args)); - ret->val = !ret->val; - return ret; +BUILTIN_PROC_DEF(num_inexact) { + ARGS_EXACTLY_ONE; + if (!args->car->is_num_obj()) + throw TokenError("a number", RUN_ERR_WRONG_TYPE); + return new BoolObj(!static_cast<NumObj*>(args->car)->is_exact()); } -EvalObj *builtin_display(ArgList *args) { +BUILTIN_PROC_DEF(display) { printf("%s\n", args->car->ext_repr().c_str()); return new UnspecObj(); } @@ -204,20 +204,35 @@ class SpecialOptQuote: public SpecialOptObj { string ext_repr(); }; -EvalObj *builtin_plus(ArgList *); -EvalObj *builtin_minus(ArgList *); -EvalObj *builtin_multi(ArgList *); -EvalObj *builtin_div(ArgList *); -EvalObj *builtin_exact(ArgList *); -EvalObj *builtin_inexact(ArgList *); -EvalObj *builtin_lt(ArgList *); -EvalObj *builtin_gt(ArgList *); -EvalObj *builtin_arithmetic_eq(ArgList *); - -EvalObj *builtin_display(ArgList *); -EvalObj *builtin_cons(ArgList *); -EvalObj *builtin_car(ArgList *); -EvalObj *builtin_cdr(ArgList *); -EvalObj *builtin_list(ArgList *); +#define BUILTIN_PROC_DEF(func)\ + EvalObj *(func)(ArgList *args, const string &name) + +BUILTIN_PROC_DEF(num_add); +BUILTIN_PROC_DEF(num_sub); +BUILTIN_PROC_DEF(num_multi); +BUILTIN_PROC_DEF(num_div); + +BUILTIN_PROC_DEF(num_lt); +BUILTIN_PROC_DEF(num_gt); +BUILTIN_PROC_DEF(num_eq); + +BUILTIN_PROC_DEF(num_exact); +BUILTIN_PROC_DEF(num_inexact); + +BUILTIN_PROC_DEF(bool_not); +BUILTIN_PROC_DEF(is_boolean); + +BUILTIN_PROC_DEF(is_pair); +BUILTIN_PROC_DEF(make_pair); +BUILTIN_PROC_DEF(pair_car); +BUILTIN_PROC_DEF(pair_cdr); +BUILTIN_PROC_DEF(pair_set_car); +BUILTIN_PROC_DEF(pair_set_cdr); +BUILTIN_PROC_DEF(is_null); +BUILTIN_PROC_DEF(is_list); + +BUILTIN_PROC_DEF(display); +BUILTIN_PROC_DEF(make_list); + #endif @@ -9,29 +9,46 @@ const int EVAL_STACK_SIZE = 65536; FrameObj *eval_stack[EVAL_STACK_SIZE]; void Evaluator::add_builtin_routines() { - + #define ADD_ENTRY(name, rout) \ envt->add_binding(new SymObj(name), rout) - ADD_ENTRY("+", new BuiltinProcObj(builtin_plus, "+")); - ADD_ENTRY("-", new BuiltinProcObj(builtin_minus, "-")); - ADD_ENTRY("*", new BuiltinProcObj(builtin_multi, "*")); - ADD_ENTRY("/", new BuiltinProcObj(builtin_div, "/")); - ADD_ENTRY(">", new BuiltinProcObj(builtin_gt, ">")); - ADD_ENTRY("<", new BuiltinProcObj(builtin_lt, "<")); - ADD_ENTRY("=", new BuiltinProcObj(builtin_arithmetic_eq, "=")); - ADD_ENTRY("display", new BuiltinProcObj(builtin_display, "display")); - ADD_ENTRY("cons", new BuiltinProcObj(builtin_cons, "cons")); - ADD_ENTRY("car", new BuiltinProcObj(builtin_car, "car")); - ADD_ENTRY("cdr", new BuiltinProcObj(builtin_cdr, "cdr")); - ADD_ENTRY("list", new BuiltinProcObj(builtin_list, "list")); - ADD_ENTRY("exact?", new BuiltinProcObj(builtin_exact, "exact?")); - ADD_ENTRY("inexact?", new BuiltinProcObj(builtin_inexact, "inexact?")); +#define ADD_BUILTIN_PROC(name, rout) \ + ADD_ENTRY(name, new BuiltinProcObj(rout, name)) + ADD_ENTRY("if", new SpecialOptIf()); ADD_ENTRY("lambda", new SpecialOptLambda()); ADD_ENTRY("define", new SpecialOptDefine()); ADD_ENTRY("set!", new SpecialOptSet()); ADD_ENTRY("quote", new SpecialOptQuote()); + + ADD_BUILTIN_PROC("+", num_add); + ADD_BUILTIN_PROC("-", num_sub); + ADD_BUILTIN_PROC("*", num_multi); + ADD_BUILTIN_PROC("/", num_div); + + ADD_BUILTIN_PROC("<", num_lt); + ADD_BUILTIN_PROC(">", num_gt); + ADD_BUILTIN_PROC("=", num_eq); + + ADD_BUILTIN_PROC("exact?", num_exact); + ADD_BUILTIN_PROC("inexact?", num_inexact); + + ADD_BUILTIN_PROC("not", bool_not); + ADD_BUILTIN_PROC("boolean?", is_boolean); + + ADD_BUILTIN_PROC("pair?", is_pair); + ADD_BUILTIN_PROC("pair", make_pair); + ADD_BUILTIN_PROC("car", pair_car); + ADD_BUILTIN_PROC("cdr", pair_cdr); + ADD_BUILTIN_PROC("set-car!", pair_set_car); + ADD_BUILTIN_PROC("set-cdr!", pair_set_cdr); + ADD_BUILTIN_PROC("null?", is_null); + ADD_BUILTIN_PROC("list?", is_list); + + ADD_BUILTIN_PROC("display", display); + ADD_BUILTIN_PROC("list", make_list); + } Evaluator::Evaluator() { @@ -71,7 +88,7 @@ EvalObj *Evaluator::run_expr(Cons *prog) { Continuation *cont = NULL; // envt is this->envt push(pc, top_ptr, envt); - + while((*eval_stack)->is_ret_addr()) { for (; pc && pc->skip; pc = pc->next); @@ -82,7 +99,7 @@ EvalObj *Evaluator::run_expr(Cons *prog) { Cons *args = empty_list; while (!(*(--top_ptr))->is_ret_addr()) args = new Cons(static_cast<EvalObj*>(*top_ptr), args); - //< static_cast because the while condition + //< static_cast because the while condition RetAddr *ret_addr = static_cast<RetAddr*>(*top_ptr); if (!ret_addr->addr) { @@ -47,6 +47,10 @@ bool EvalObj::is_num_obj() { return otype & CLS_NUM_OBJ; } +bool EvalObj::is_bool_obj() { + return otype & CLS_BOOL_OBJ; +} + #ifdef DEBUG string EvalObj::_debug_repr() { return ext_repr(); @@ -163,7 +167,7 @@ string ProcObj::_debug_repr() { return ext_repr(); } SpecialOptObj::SpecialOptObj() : OptObj() {} -BoolObj::BoolObj(bool _val) : EvalObj(CLS_SIM_OBJ), val(_val) {} +BoolObj::BoolObj(bool _val) : EvalObj(CLS_SIM_OBJ | CLS_BOOL_OBJ), val(_val) {} bool BoolObj::is_true() { return val; } @@ -242,7 +246,7 @@ Cons *BuiltinProcObj::call(ArgList *args, Environment * &envt, Continuation * &cont, FrameObj ** &top_ptr) { Cons *ret_addr = static_cast<RetAddr*>(*top_ptr)->addr; - *top_ptr++ = handler(TO_CONS(args->cdr)); + *top_ptr++ = handler(TO_CONS(args->cdr), name); return ret_addr->next; // Move to the next instruction } @@ -24,6 +24,7 @@ const int CLS_CONS_OBJ = 1 << 1; const int CLS_SYM_OBJ = 1 << 2; const int CLS_OPT_OBJ = 1 << 3; const int CLS_NUM_OBJ = 1 << 4; +const int CLS_BOOL_OBJ = 1 << 5; #define TO_CONS(ptr) \ @@ -96,6 +97,8 @@ class EvalObj : public FrameObj { bool is_cons_obj(); /** Check if the object is a number */ bool is_num_obj(); + /** Check if the object is a boolean */ + bool is_bool_obj(); virtual void prepare(Cons *pc); /** Any EvalObj has its external representation */ virtual string ext_repr() = 0; @@ -247,7 +250,7 @@ class SpecialOptObj: public OptObj { SpecialOptObj(); }; -typedef EvalObj* (*BuiltinProc)(ArgList *); +typedef EvalObj* (*BuiltinProc)(ArgList *, const string &); /** @class BuiltinProcObj * Wrapping class for builtin procedures (arithmetic operators, etc.) */ |