diff options
-rw-r--r-- | builtin.cpp | 73 | ||||
-rw-r--r-- | consts.cpp | 8 | ||||
-rw-r--r-- | consts.h | 8 | ||||
-rw-r--r-- | eval.cpp | 3 | ||||
-rw-r--r-- | main.cpp | 7 | ||||
-rw-r--r-- | model.cpp | 26 | ||||
-rw-r--r-- | parser.cpp | 6 |
7 files changed, 97 insertions, 34 deletions
diff --git a/builtin.cpp b/builtin.cpp index 806d911..374f3f2 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -46,34 +46,44 @@ SpecialOptIf::SpecialOptIf() : SpecialOptObj() {} void SpecialOptIf::prepare(Cons *pc) { state = 0; // Prepared + pc = pc->cdr; + if (pc == empty_list) + throw TokenError("if", SYN_ERR_MISS_OR_EXTRA_EXP); pc->skip = false; - pc->cdr->skip = true; - if (pc->cdr->cdr != empty_list) - pc->cdr->cdr->skip = true; + + pc = 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; } void SpecialOptIf::pre_call(ArgList *args, Cons *pc, Environment *envt) { // static_cast because it's a call invocation - pc = static_cast<Cons*>(pc->car); + pc = static_cast<Cons*>(pc->car)->cdr; + // Condition evaluated and the decision is made state = 1; + if (args->cdr->car->is_true()) { - pc = pc->cdr; pc->skip = true; - pc->cdr->skip = false; - if (pc->cdr->cdr != empty_list) - pc->cdr->cdr->skip = true; // Eval the former + pc = pc->cdr; + pc->skip = false; + if (pc->cdr != empty_list) + pc->cdr->skip = true; // Eval the former } else { - pc = pc->cdr; pc->skip = true; + pc = pc->cdr; pc->cdr->skip = true; - if (pc->cdr->cdr != empty_list) - pc->cdr->cdr->skip = false; //Eval the latter + if (pc->cdr != empty_list) + pc->cdr->skip = false; //Eval the latter } } @@ -120,8 +130,15 @@ void SpecialOptLambda::prepare(Cons *pc) { Cons *SpecialOptLambda::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); + + if (pc->cdr == empty_list) + throw TokenError("lambda", SYN_ERR_EMPTY_PARA_LIST); + if (pc->cdr->cdr == empty_list) + throw TokenError("lambda", SYN_ERR_MISS_OR_EXTRA_EXP); + SymbolList *para_list = static_cast<SymbolList*>(pc->cdr->car); // Clear the flag to avoid side-effects (e.g. proc calling) FILL_MARKS(pc, false); @@ -144,10 +161,16 @@ string SpecialOptLambda::_debug_repr() { return ext_repr(); } SpecialOptDefine::SpecialOptDefine() : SpecialOptObj() {} 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 { - pc->cdr->skip = true; // Skip the identifier - pc->cdr->cdr->skip = false; + pc = 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; } // Procedure definition else FILL_MARKS(pc, true); // Skip all parts } @@ -172,8 +195,9 @@ Cons *SpecialOptDefine::call(ArgList *args, Environment * &envt, { // static_cast because of is_simple_obj() is false Cons *plst = static_cast<Cons*>(pc->cdr->car); + if (plst == empty_list) - throw NormalError(SYN_ERR_ID_EXPECTED); + throw TokenError("if", SYN_ERR_EMPTY_PARA_LIST); if (!plst->car->is_sym_obj()) throw TokenError(first->ext_repr(), SYN_ERR_NOT_AN_ID); @@ -181,7 +205,12 @@ Cons *SpecialOptDefine::call(ArgList *args, Environment * &envt, ArgList *para_list = 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 + + if (body == empty_list) + throw TokenError("define", SYN_ERR_MISS_OR_EXTRA_EXP); + for (Cons *ptr = body; ptr != empty_list; ptr = ptr->cdr) ptr->next = NULL; // Make each expression a orphan @@ -199,9 +228,17 @@ string SpecialOptDefine::_debug_repr() { return ext_repr(); } #endif void SpecialOptSet::prepare(Cons *pc) { - // TODO: check number of arguments - pc->cdr->skip = true; // Skip the identifier - pc->cdr->cdr->skip = false; + pc = pc->cdr; + if (pc == empty_list) + throw TokenError("set!", SYN_ERR_MISS_OR_EXTRA_EXP); + + pc->skip = true; // Skip the identifier + + pc = pc->cdr; + if (pc == empty_list) + throw TokenError("set!", SYN_ERR_MISS_OR_EXTRA_EXP); + + pc->skip = false; } Cons *SpecialOptSet::call(ArgList *args, Environment * &envt, @@ -216,7 +253,7 @@ Cons *SpecialOptSet::call(ArgList *args, Environment * &envt, SymObj *id = static_cast<SymObj*>(first); bool flag = envt->add_binding(id, args->cdr->car, false); - if (!flag) throw TokenError(id->ext_repr(), SYN_ERR_UNBOUND_VAR); + if (!flag) throw TokenError(id->ext_repr(), RUN_ERR_UNBOUND_VAR); *top_ptr++ = new UnspecObj(); return ret_addr->next; } @@ -3,6 +3,10 @@ const char *SYN_ERR_MSG[] = { "\"%s\" is not an valid identifier", "Cannot apply the operation \"%s\"", - "An identifier is expected", - "Unbound variable: \"%s\"" + "Unbound variable: \"%s\"", + "Missing or extra expression in (%s)", + "Empty parameter list in (%s)", + "Wrong number of arguments to procedure (%s)", + "Illegal empty combination ()", + "Unexpected \")\"" }; @@ -4,8 +4,12 @@ enum ErrCode { SYN_ERR_NOT_AN_ID, SYN_ERR_CAN_NOT_APPLY, - SYN_ERR_ID_EXPECTED, - SYN_ERR_UNBOUND_VAR + RUN_ERR_UNBOUND_VAR, + SYN_ERR_MISS_OR_EXTRA_EXP, + SYN_ERR_EMPTY_PARA_LIST, + RUN_ERR_WRONG_NUM_OF_ARGS, + SYN_ERR_EMPTY_COMB, + READ_ERR_UNEXPECTED_RIGHT_BRACKET }; extern const char *SYN_ERR_MSG[]; @@ -43,6 +43,9 @@ void push(Cons * &pc, FrameObj ** &top_ptr, Environment *envt) { } else // Operational Invocation { + if (pc->car == empty_list) + throw NormalError(SYN_ERR_EMPTY_COMB); + *top_ptr++ = new RetAddr(pc); // Push the return address // static_cast because of is_simple_obj() is false pc = static_cast<Cons*>(pc->car); // Go deeper to enter the call @@ -23,11 +23,12 @@ int main() { while (1) { - Cons *tree = ast->absorb(tk); - if (!tree) break; - //tree_print(tree); + printf("Sonsi> "); try { + Cons *tree = ast->absorb(tk); + if (!tree) break; + //tree_print(tree); printf("%s\n", eval->run_expr(tree)->ext_repr().c_str()); } catch (GeneralError &e) @@ -1,5 +1,7 @@ #include <cstdio> #include "model.h" +#include "exc.h" +#include "consts.h" FrameObj::FrameObj(ClassType _ftype) : ftype(_ftype) {} @@ -94,19 +96,26 @@ ProcObj::ProcObj(ASTList *_body, SymbolList *_para_list) : OptObj(), body(_body), envt(_envt), para_list(_para_list) {} -Cons *ProcObj::call(ArgList *args, Environment * &_envt, +Cons *ProcObj::call(ArgList *args, Environment * &genvt, Continuation * &cont, FrameObj ** &top_ptr) { // Create a new continuation // static_cast see `call` invocation in eval.cpp Cons *ret_addr = static_cast<RetAddr*>(*top_ptr)->addr; - Continuation *ncont = new Continuation(_envt, ret_addr, cont, body); - cont = ncont; // Add to the cont chain - _envt = new Environment(envt); // Create local env and recall the closure - // TODO: Compare the arguments to the parameters + 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 para_list is already checked - for (Cons *ptr = args->cdr, *ppar = para_list; - ptr != empty_list; ptr = ptr->cdr, ppar = ppar->cdr) + Cons *ptr, *ppar; + for (ptr = args->cdr, ppar = para_list; + ptr != empty_list && ppar != empty_list; + ptr = ptr->cdr, ppar = ppar->cdr) _envt->add_binding(static_cast<SymObj*>(ppar->car), ptr->car); + + if (ptr != empty_list || ppar != empty_list) + throw TokenError("", RUN_ERR_WRONG_NUM_OF_ARGS); + + genvt = _envt; + cont = _cont; *top_ptr++ = new RetAddr(NULL); // Mark the entrance of a cont return body; // Move pc to the proc entry point } @@ -159,7 +168,8 @@ EvalObj *Environment::get_obj(EvalObj *obj) { bool has_key = ptr->binding.count(name); if (has_key) return ptr->binding[name]; } - return NULL; // Object not found + // Object not found + throw TokenError(name, RUN_ERR_UNBOUND_VAR); } Continuation::Continuation(Environment *_envt, Cons *_pc, @@ -2,6 +2,8 @@ #include <cctype> #include <sstream> #include "parser.h" +#include "exc.h" +#include "consts.h" #include "builtin.h" using std::stringstream; @@ -85,8 +87,10 @@ Cons *ASTGenerator::absorb(Tokenizor *tk) { else if (token == ")") { Cons *lst = empty_list; - while (*(--top_ptr)) + while (top_ptr >= parse_stack && *(--top_ptr)) lst = new Cons(*top_ptr, lst); // Collect the list + if (top_ptr < parse_stack) + throw NormalError(READ_ERR_UNEXPECTED_RIGHT_BRACKET); *top_ptr++ = lst; } else *top_ptr++ = ASTGenerator::to_obj(token); |