aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTeddy <ted.sybil@gmail.com>2013-08-04 23:35:59 +0800
committerTeddy <ted.sybil@gmail.com>2013-08-04 23:35:59 +0800
commit645549b8a42844fc5a8042a4808c8ebf5050d7da (patch)
tree6f96ef92e16f332a6eb3860450404903865a12fe
parentacb298c7f864f9862859320555b416c97632d2fa (diff)
added support for `cons`, `car`, `cdr`
-rw-r--r--builtin.cpp103
-rw-r--r--builtin.h3
-rw-r--r--consts.cpp3
-rw-r--r--consts.h3
-rw-r--r--eval.cpp5
-rw-r--r--main.cpp2
-rw-r--r--model.cpp18
-rw-r--r--model.h9
-rw-r--r--parser.cpp6
9 files changed, 103 insertions, 49 deletions
diff --git a/builtin.cpp b/builtin.cpp
index 374f3f2..f1b518f 100644
--- a/builtin.cpp
+++ b/builtin.cpp
@@ -47,50 +47,50 @@ SpecialOptIf::SpecialOptIf() : SpecialOptObj() {}
void SpecialOptIf::prepare(Cons *pc) {
state = 0; // Prepared
- pc = pc->cdr;
+ pc = TO_CONS(pc->cdr);
if (pc == empty_list)
throw TokenError("if", SYN_ERR_MISS_OR_EXTRA_EXP);
pc->skip = false;
- pc = pc->cdr;
+ pc = TO_CONS(pc->cdr);
if (pc == empty_list)
throw TokenError("if", SYN_ERR_MISS_OR_EXTRA_EXP);
pc->skip = true;
if (pc->cdr != empty_list)
- pc->cdr->skip = true;
+ TO_CONS(pc->cdr)->skip = true;
}
void SpecialOptIf::pre_call(ArgList *args, Cons *pc,
Environment *envt) {
// static_cast because it's a call invocation
- pc = static_cast<Cons*>(pc->car)->cdr;
+ pc = TO_CONS(TO_CONS(pc->car)->cdr);
// Condition evaluated and the decision is made
state = 1;
- if (args->cdr->car->is_true())
+ if (TO_CONS(args->cdr)->car->is_true())
{
pc->skip = true;
- pc = pc->cdr;
+ pc = TO_CONS(pc->cdr);
pc->skip = false;
if (pc->cdr != empty_list)
- pc->cdr->skip = true; // Eval the former
+ TO_CONS(pc->cdr)->skip = true; // Eval the former
}
else
{
pc->skip = true;
- pc = pc->cdr;
- pc->cdr->skip = true;
+ pc = TO_CONS(pc->cdr);
+ TO_CONS(pc->cdr)->skip = true;
if (pc->cdr != empty_list)
- pc->cdr->skip = false; //Eval the latter
+ TO_CONS(pc->cdr)->skip = false; //Eval the latter
}
}
EvalObj *SpecialOptIf::post_call(ArgList *args, Cons *pc,
Environment *envt) {
// Value already evaluated, so just return it
- return args->cdr->car;
+ return TO_CONS(args->cdr)->car;
}
Cons *SpecialOptIf::call(ArgList *args, Environment * &envt,
@@ -119,7 +119,8 @@ string SpecialOptIf::_debug_repr() { return ext_repr(); }
SpecialOptLambda::SpecialOptLambda() : SpecialOptObj() {}
#define FILL_MARKS(pc, flag) \
- for (Cons *ptr = pc->cdr; ptr != empty_list; ptr = ptr->cdr) \
+ for (Cons *ptr = TO_CONS(pc->cdr); \
+ ptr != empty_list; ptr = TO_CONS(ptr->cdr)) \
ptr->skip = flag
void SpecialOptLambda::prepare(Cons *pc) {
@@ -136,16 +137,16 @@ Cons *SpecialOptLambda::call(ArgList *args, Environment * &envt,
if (pc->cdr == empty_list)
throw TokenError("lambda", SYN_ERR_EMPTY_PARA_LIST);
- if (pc->cdr->cdr == empty_list)
+ if (TO_CONS(pc->cdr)->cdr == empty_list)
throw TokenError("lambda", SYN_ERR_MISS_OR_EXTRA_EXP);
- SymbolList *para_list = static_cast<SymbolList*>(pc->cdr->car);
+ SymbolList *para_list = static_cast<SymbolList*>(TO_CONS(pc->cdr)->car);
// Clear the flag to avoid side-effects (e.g. proc calling)
FILL_MARKS(pc, false);
// store a list of expressions inside <body>
- ASTList *body = pc->cdr->cdr; // Truncate the expression list
- for (Cons *ptr = body; ptr != empty_list; ptr = ptr->cdr)
+ ASTList *body = TO_CONS(TO_CONS(pc->cdr)->cdr); // Truncate the expression list
+ for (Cons *ptr = body; ptr != empty_list; ptr = TO_CONS(ptr->cdr))
ptr->next = NULL; // Make each expression an orphan
*top_ptr++ = new ProcObj(body, envt, para_list);
@@ -164,13 +165,13 @@ void SpecialOptDefine::prepare(Cons *pc) {
if (pc->cdr == empty_list)
throw TokenError("define", SYN_ERR_MISS_OR_EXTRA_EXP);
- if (pc->cdr->car->is_simple_obj()) // Simple value assignment
+ if (TO_CONS(pc->cdr)->car->is_simple_obj()) // Simple value assignment
{
- pc = pc->cdr;
+ pc = TO_CONS(pc->cdr);
if (pc->cdr == empty_list)
throw TokenError("define", SYN_ERR_MISS_OR_EXTRA_EXP);
pc->skip = true; // Skip the identifier
- pc->cdr->skip = false;
+ TO_CONS(pc->cdr)->skip = false;
} // Procedure definition
else FILL_MARKS(pc, true); // Skip all parts
}
@@ -182,19 +183,19 @@ Cons *SpecialOptDefine::call(ArgList *args, Environment * &envt,
EvalObj *obj;
SymObj *id;
// TODO: check identifier
- EvalObj *first = pc->cdr->car;
+ EvalObj *first = TO_CONS(pc->cdr)->car;
if (first->is_simple_obj())
{
if (!first->is_sym_obj())
throw TokenError(first->ext_repr(), SYN_ERR_NOT_AN_ID);
id = static_cast<SymObj*>(first);
- obj = args->cdr->car;
+ obj = TO_CONS(args->cdr)->car;
}
else
{
// static_cast because of is_simple_obj() is false
- Cons *plst = static_cast<Cons*>(pc->cdr->car);
+ Cons *plst = static_cast<Cons*>(TO_CONS(pc->cdr)->car);
if (plst == empty_list)
throw TokenError("if", SYN_ERR_EMPTY_PARA_LIST);
@@ -202,16 +203,16 @@ Cons *SpecialOptDefine::call(ArgList *args, Environment * &envt,
throw TokenError(first->ext_repr(), SYN_ERR_NOT_AN_ID);
id = static_cast<SymObj*>(plst->car);
- ArgList *para_list = plst->cdr;
+ ArgList *para_list = TO_CONS(plst->cdr);
// Clear the flag to avoid side-effects (e.g. proc calling)
FILL_MARKS(pc, false);
- ASTList *body = pc->cdr->cdr; // Truncate the expression list
+ ASTList *body = TO_CONS(TO_CONS(pc->cdr)->cdr); // Truncate the expression list
if (body == empty_list)
throw TokenError("define", SYN_ERR_MISS_OR_EXTRA_EXP);
- for (Cons *ptr = body; ptr != empty_list; ptr = ptr->cdr)
+ for (Cons *ptr = body; ptr != empty_list; ptr = TO_CONS(ptr->cdr))
ptr->next = NULL; // Make each expression a orphan
obj = new ProcObj(body, envt, para_list);
@@ -228,13 +229,13 @@ string SpecialOptDefine::_debug_repr() { return ext_repr(); }
#endif
void SpecialOptSet::prepare(Cons *pc) {
- pc = pc->cdr;
+ pc = TO_CONS(pc->cdr);
if (pc == empty_list)
throw TokenError("set!", SYN_ERR_MISS_OR_EXTRA_EXP);
pc->skip = true; // Skip the identifier
- pc = pc->cdr;
+ pc = TO_CONS(pc->cdr);
if (pc == empty_list)
throw TokenError("set!", SYN_ERR_MISS_OR_EXTRA_EXP);
@@ -245,14 +246,14 @@ Cons *SpecialOptSet::call(ArgList *args, Environment * &envt,
Continuation * &cont, FrameObj ** &top_ptr) {
Cons *ret_addr = static_cast<RetAddr*>(*top_ptr)->addr;
Cons *pc = static_cast<Cons*>(ret_addr->car);
- EvalObj *first = pc->cdr->car;
+ EvalObj *first = TO_CONS(pc->cdr)->car;
if (!first->is_sym_obj())
throw TokenError(first->ext_repr(), SYN_ERR_NOT_AN_ID);
SymObj *id = static_cast<SymObj*>(first);
- bool flag = envt->add_binding(id, args->cdr->car, false);
+ bool flag = envt->add_binding(id, TO_CONS(args->cdr)->car, false);
if (!flag) throw TokenError(id->ext_repr(), RUN_ERR_UNBOUND_VAR);
*top_ptr++ = new UnspecObj();
return ret_addr->next;
@@ -266,10 +267,39 @@ string SpecialOptSet::ext_repr() { return string("#<Builtin Macro: set!>"); }
string SpecialOptSet::_debug_repr() { return ext_repr(); }
#endif
+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);
+
+ 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);
+ if (!args->car->is_cons_obj())
+ throw TokenError("pair", 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);
+ if (!args->car->is_cons_obj())
+ throw TokenError("pair", RUN_ERR_WRONG_TYPE);
+
+ return TO_CONS(args->car)->cdr;
+}
+
EvalObj *builtin_plus(ArgList *args) {
// TODO: type conversion and proper arithmetic
int res = 0;
- for (Cons *ptr = args; ptr != empty_list; ptr = ptr->cdr)
+ for (Cons *ptr = args; ptr != empty_list; ptr = TO_CONS(ptr->cdr))
res += dynamic_cast<IntObj*>(ptr->car)->val;
return new IntObj(res);
}
@@ -277,7 +307,8 @@ EvalObj *builtin_plus(ArgList *args) {
EvalObj *builtin_minus(ArgList *args) {
// TODO: type conversion and proper arithmetic
int res = dynamic_cast<IntObj*>(args->car)->val;
- for (Cons *ptr = args->cdr; ptr != empty_list; ptr = ptr->cdr)
+ for (Cons *ptr = TO_CONS(args->cdr);
+ ptr != empty_list; ptr = TO_CONS(ptr->cdr))
res -= dynamic_cast<IntObj*>(ptr->car)->val;
return new IntObj(res);
}
@@ -285,7 +316,7 @@ EvalObj *builtin_minus(ArgList *args) {
EvalObj *builtin_times(ArgList *args) {
// TODO: type conversion and proper arithmetic
int res = 1;
- for (Cons *ptr = args; ptr != empty_list; ptr = ptr->cdr)
+ for (Cons *ptr = args; ptr != empty_list; ptr = TO_CONS(ptr->cdr))
res *= dynamic_cast<IntObj*>(ptr->car)->val;
return new IntObj(res);
}
@@ -293,24 +324,24 @@ EvalObj *builtin_times(ArgList *args) {
EvalObj *builtin_div(ArgList *args) {
// TODO: type conversion and proper arithmetic
int res = dynamic_cast<IntObj*>(args->car)->val;
- for (Cons *ptr = args->cdr; ptr != empty_list; ptr = ptr->cdr)
+ for (Cons *ptr = TO_CONS(args->cdr); ptr != empty_list; ptr = TO_CONS(ptr->cdr))
res /= dynamic_cast<IntObj*>(ptr->car)->val;
return new IntObj(res);
}
EvalObj *builtin_lt(ArgList *args) {
return new BoolObj(dynamic_cast<IntObj*>(args->car)->val <
- dynamic_cast<IntObj*>(args->cdr->car)->val);
+ dynamic_cast<IntObj*>(TO_CONS(args->cdr)->car)->val);
}
EvalObj *builtin_gt(ArgList *args) {
return new BoolObj(dynamic_cast<IntObj*>(args->car)->val >
- dynamic_cast<IntObj*>(args->cdr->car)->val);
+ dynamic_cast<IntObj*>(TO_CONS(args->cdr)->car)->val);
}
EvalObj *builtin_arithmetic_eq(ArgList *args) {
return new BoolObj(dynamic_cast<IntObj*>(args->car)->val ==
- dynamic_cast<IntObj*>(args->cdr->car)->val);
+ dynamic_cast<IntObj*>(TO_CONS(args->cdr)->car)->val);
}
EvalObj *builtin_display(ArgList *args) {
diff --git a/builtin.h b/builtin.h
index 92b2fe0..8d2a6a0 100644
--- a/builtin.h
+++ b/builtin.h
@@ -133,5 +133,8 @@ 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 *);
#endif
diff --git a/consts.cpp b/consts.cpp
index c7058b0..ec3ed01 100644
--- a/consts.cpp
+++ b/consts.cpp
@@ -8,5 +8,6 @@ const char *SYN_ERR_MSG[] = {
"Empty parameter list in (%s)",
"Wrong number of arguments to procedure (%s)",
"Illegal empty combination ()",
- "Unexpected \")\""
+ "Unexpected \")\"",
+ "Wrong type (expecting %s)"
};
diff --git a/consts.h b/consts.h
index 5e3f43d..5991317 100644
--- a/consts.h
+++ b/consts.h
@@ -9,7 +9,8 @@ enum ErrCode {
SYN_ERR_EMPTY_PARA_LIST,
RUN_ERR_WRONG_NUM_OF_ARGS,
SYN_ERR_EMPTY_COMB,
- READ_ERR_UNEXPECTED_RIGHT_BRACKET
+ READ_ERR_UNEXPECTED_RIGHT_BRACKET,
+ RUN_ERR_WRONG_TYPE
};
extern const char *SYN_ERR_MSG[];
diff --git a/eval.cpp b/eval.cpp
index efd1114..de06209 100644
--- a/eval.cpp
+++ b/eval.cpp
@@ -21,6 +21,9 @@ void Evaluator::add_builtin_routines() {
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("if", new SpecialOptIf());
ADD_ENTRY("lambda", new SpecialOptLambda());
ADD_ENTRY("define", new SpecialOptDefine());
@@ -79,7 +82,7 @@ EvalObj *Evaluator::run_expr(Cons *prog) {
RetAddr *ret_addr = static_cast<RetAddr*>(*top_ptr);
if (!ret_addr->addr)
{
- Cons *nexp = cont->proc_body->cdr;
+ Cons *nexp = TO_CONS(cont->proc_body->cdr);
cont->proc_body = nexp;
if (nexp == empty_list)
{
diff --git a/main.cpp b/main.cpp
index e8fe418..230d077 100644
--- a/main.cpp
+++ b/main.cpp
@@ -11,7 +11,7 @@ void tree_print(Cons *ptr) {
if (!ptr || ptr == empty_list) return;
ptr->_debug_print();
tree_print(dynamic_cast<Cons*>(ptr->car));
- tree_print(ptr->cdr);
+ tree_print(TO_CONS(ptr->cdr));
}
#endif
diff --git a/model.cpp b/model.cpp
index 2132d1f..fab17d6 100644
--- a/model.cpp
+++ b/model.cpp
@@ -35,6 +35,10 @@ bool EvalObj::is_opt_obj() {
return otype & CLS_OPT_OBJ;
}
+bool EvalObj::is_cons_obj() {
+ return otype & CLS_CONS_OBJ;
+}
+
#ifdef DEBUG
void EvalObj::_debug_print() {
printf("mem: 0x%llX\n%s\n\n", (unsigned long long)this,
@@ -46,11 +50,13 @@ bool EvalObj::is_true() {
return true;
}
-Cons::Cons(EvalObj *_car, Cons *_cdr) :
+Cons::Cons(EvalObj *_car, EvalObj *_cdr) :
EvalObj(CLS_CONS_OBJ), car(_car), cdr(_cdr), skip(false),
- next(cdr == empty_list ? NULL : cdr) {}
+ next(NULL) {}
-string Cons::ext_repr() { return string("#<Cons>"); }
+string Cons::ext_repr() {
+ return "(" + car->ext_repr() + " . " + cdr->ext_repr() + ")";
+}
#ifdef DEBUG
string Cons::_debug_repr() { return ext_repr(); }
@@ -106,9 +112,9 @@ Cons *ProcObj::call(ArgList *args, Environment * &genvt,
Environment *_envt = new Environment(envt);
// static_cast<SymObj*> because the para_list is already checked
Cons *ptr, *ppar;
- for (ptr = args->cdr, ppar = para_list;
+ for (ptr = TO_CONS(args->cdr), ppar = para_list;
ptr != empty_list && ppar != empty_list;
- ptr = ptr->cdr, ppar = ppar->cdr)
+ ptr = TO_CONS(ptr->cdr), ppar = TO_CONS(ppar->cdr))
_envt->add_binding(static_cast<SymObj*>(ppar->car), ptr->car);
if (ptr != empty_list || ppar != empty_list)
@@ -137,7 +143,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(args->cdr);
+ *top_ptr++ = handler(TO_CONS(args->cdr));
return ret_addr->next; // Move to the next instruction
}
diff --git a/model.h b/model.h
index ebae3d6..a98a475 100644
--- a/model.h
+++ b/model.h
@@ -19,6 +19,9 @@ static const int CLS_CONS_OBJ = 1 << 1;
static const int CLS_SYM_OBJ = 1 << 2;
static const int CLS_OPT_OBJ = 1 << 3;
+#define TO_CONS(ptr) \
+ (static_cast<Cons*>(ptr))
+
/** @class FrameObj
* Objects that can be held in the evaluation stack
*/
@@ -76,6 +79,8 @@ class EvalObj : public FrameObj {
bool is_sym_obj();
/** Check if the object is an operator */
bool is_opt_obj();
+ /** Check if the object is a Cons */
+ bool is_cons_obj();
virtual void prepare(Cons *pc);
/** Any EvalObj has its external representation */
virtual string ext_repr() = 0;
@@ -94,11 +99,11 @@ class EvalObj : public FrameObj {
class Cons : public EvalObj {
public:
EvalObj *car; /**< car (as in Scheme) */
- Cons *cdr; /**< cdr (as in Scheme) */
+ EvalObj *cdr; /**< cdr (as in Scheme) */
bool skip; /**< Wether to skip the current branch */
Cons* next; /**< The next branch in effect */
- Cons(EvalObj *car, Cons *cdr); /**< Create a Cons (car . cdr) */
+ Cons(EvalObj *car, EvalObj *cdr); /**< Create a Cons (car . cdr) */
#ifdef DEBUG
void _debug_print();
string _debug_repr();
diff --git a/parser.cpp b/parser.cpp
index 8de812f..f4de5a2 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -103,7 +103,11 @@ Cons *ASTGenerator::absorb(Tokenizor *tk) {
{
Cons *lst = empty_list;
while (top_ptr >= parse_stack && *(--top_ptr))
- lst = new Cons(*top_ptr, lst); // Collect the list
+ {
+ Cons *_lst = new Cons(*top_ptr, lst); // Collect the list
+ _lst->next = lst == empty_list ? NULL : lst;
+ lst = _lst;
+ }
if (top_ptr < parse_stack)
throw NormalError(READ_ERR_UNEXPECTED_RIGHT_BRACKET);
*top_ptr++ = lst;