aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin.cpp73
-rw-r--r--consts.cpp8
-rw-r--r--consts.h8
-rw-r--r--eval.cpp3
-rw-r--r--main.cpp7
-rw-r--r--model.cpp26
-rw-r--r--parser.cpp6
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;
}
diff --git a/consts.cpp b/consts.cpp
index 894482e..c7058b0 100644
--- a/consts.cpp
+++ b/consts.cpp
@@ -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 \")\""
};
diff --git a/consts.h b/consts.h
index a4f4ae3..5e3f43d 100644
--- a/consts.h
+++ b/consts.h
@@ -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[];
diff --git a/eval.cpp b/eval.cpp
index dd4be00..efd1114 100644
--- a/eval.cpp
+++ b/eval.cpp
@@ -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
diff --git a/main.cpp b/main.cpp
index 31d7943..e8fe418 100644
--- a/main.cpp
+++ b/main.cpp
@@ -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)
diff --git a/model.cpp b/model.cpp
index d53a9bf..2132d1f 100644
--- a/model.cpp
+++ b/model.cpp
@@ -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,
diff --git a/parser.cpp b/parser.cpp
index e1724c3..ecfafab 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -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);