aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTeddy <ted.sybil@gmail.com>2013-08-04 11:50:41 +0800
committerTeddy <ted.sybil@gmail.com>2013-08-04 11:50:41 +0800
commit65f17438de5983ca010e10b4b24c5da65756a9b5 (patch)
treedfa88443d6cd10a14f587377f101e14359e98f56
parentd42c4bd97982c1252c5ad638a11aea5319c4be7f (diff)
added exception facilities
-rw-r--r--Makefile2
-rw-r--r--builtin.cpp29
-rw-r--r--consts.cpp8
-rw-r--r--consts.h13
-rw-r--r--eval.cpp11
-rw-r--r--exc.cpp16
-rw-r--r--exc.h37
-rw-r--r--main.cpp11
-rw-r--r--model.cpp21
-rw-r--r--model.h16
10 files changed, 144 insertions, 20 deletions
diff --git a/Makefile b/Makefile
index ea9d9a9..4c2071c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-main: main.o parser.o builtin.o model.o eval.o
+main: main.o parser.o builtin.o model.o eval.o exc.o consts.o
g++ -o main $^ -pg
.cpp.o:
diff --git a/builtin.cpp b/builtin.cpp
index 1ac0cf2..806d911 100644
--- a/builtin.cpp
+++ b/builtin.cpp
@@ -1,3 +1,5 @@
+#include "exc.h"
+#include "consts.h"
#include "builtin.h"
#include <cstdio>
#include <sstream>
@@ -120,7 +122,7 @@ 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);
- SymbolList *para_list = dynamic_cast<SymbolList*>(pc->cdr->car); // parameter list
+ SymbolList *para_list = static_cast<SymbolList*>(pc->cdr->car);
// Clear the flag to avoid side-effects (e.g. proc calling)
FILL_MARKS(pc, false);
@@ -157,16 +159,25 @@ Cons *SpecialOptDefine::call(ArgList *args, Environment * &envt,
EvalObj *obj;
SymObj *id;
// TODO: check identifier
- if (pc->cdr->car->is_simple_obj())
+ EvalObj *first = pc->cdr->car;
+ if (first->is_simple_obj())
{
- id = dynamic_cast<SymObj*>(pc->cdr->car);
+ if (!first->is_sym_obj())
+ throw TokenError(first->ext_repr(), SYN_ERR_NOT_AN_ID);
+
+ id = static_cast<SymObj*>(first);
obj = args->cdr->car;
}
else
{
// static_cast because of is_simple_obj() is false
Cons *plst = static_cast<Cons*>(pc->cdr->car);
- id = dynamic_cast<SymObj*>(plst->car);
+ if (plst == empty_list)
+ throw NormalError(SYN_ERR_ID_EXPECTED);
+ if (!plst->car->is_sym_obj())
+ throw TokenError(first->ext_repr(), SYN_ERR_NOT_AN_ID);
+
+ id = static_cast<SymObj*>(plst->car);
ArgList *para_list = plst->cdr;
// Clear the flag to avoid side-effects (e.g. proc calling)
FILL_MARKS(pc, false);
@@ -197,9 +208,15 @@ 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);
- SymObj *id = dynamic_cast<SymObj*>(pc->cdr->car);
+ EvalObj *first = 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);
- // TODO: throw an exc "unbound variable"
+ if (!flag) throw TokenError(id->ext_repr(), SYN_ERR_UNBOUND_VAR);
*top_ptr++ = new UnspecObj();
return ret_addr->next;
}
diff --git a/consts.cpp b/consts.cpp
new file mode 100644
index 0000000..894482e
--- /dev/null
+++ b/consts.cpp
@@ -0,0 +1,8 @@
+#include "consts.h"
+
+const char *SYN_ERR_MSG[] = {
+ "\"%s\" is not an valid identifier",
+ "Cannot apply the operation \"%s\"",
+ "An identifier is expected",
+ "Unbound variable: \"%s\""
+};
diff --git a/consts.h b/consts.h
new file mode 100644
index 0000000..a4f4ae3
--- /dev/null
+++ b/consts.h
@@ -0,0 +1,13 @@
+#ifndef CONSTS_H
+#define CONSTS_H
+
+enum ErrCode {
+ SYN_ERR_NOT_AN_ID,
+ SYN_ERR_CAN_NOT_APPLY,
+ SYN_ERR_ID_EXPECTED,
+ SYN_ERR_UNBOUND_VAR
+};
+
+extern const char *SYN_ERR_MSG[];
+
+#endif
diff --git a/eval.cpp b/eval.cpp
index e536f8f..dd4be00 100644
--- a/eval.cpp
+++ b/eval.cpp
@@ -1,5 +1,7 @@
#include "eval.h"
#include "builtin.h"
+#include "exc.h"
+#include "consts.h"
#include <cstdio>
extern Cons *empty_list;
@@ -87,7 +89,14 @@ EvalObj *Evaluator::run_expr(Cons *prog) {
top_ptr++;
}
else
- pc = dynamic_cast<OptObj*>(args->car)->call(args, envt, cont, top_ptr);
+ {
+ EvalObj *opt = args->car;
+ if (opt->is_opt_obj())
+ pc = static_cast<OptObj*>(opt)->
+ call(args, envt, cont, top_ptr);
+ else
+ throw TokenError(opt->ext_repr(), SYN_ERR_CAN_NOT_APPLY);
+ }
}
}
// static_cast because the previous while condition
diff --git a/exc.cpp b/exc.cpp
new file mode 100644
index 0000000..648326e
--- /dev/null
+++ b/exc.cpp
@@ -0,0 +1,16 @@
+#include "exc.h"
+#include <cstdio>
+
+SyntaxError::SyntaxError(ErrCode _code) : code(_code) {}
+
+string SyntaxError::get_msg() { return this->msg; }
+
+TokenError::TokenError(string token, ErrCode code) : SyntaxError(code) {
+ static char buffer[1024]; // should be enough
+ sprintf(buffer, SYN_ERR_MSG[code], token.c_str());
+ msg = buffer;
+}
+
+NormalError::NormalError(ErrCode code) : SyntaxError(code) {
+ msg = SYN_ERR_MSG[code];
+}
diff --git a/exc.h b/exc.h
new file mode 100644
index 0000000..7a6879d
--- /dev/null
+++ b/exc.h
@@ -0,0 +1,37 @@
+#ifndef EXC_H
+#define EXC_H
+
+#include "consts.h"
+#include <string>
+
+using std::string;
+
+/** @class GeneralError
+ * The top-level exception
+ */
+class GeneralError {
+ public:
+ virtual string get_msg() = 0; /**< Extract error message */
+};
+
+class SyntaxError : public GeneralError {
+ protected:
+ string msg; /**< Error mesg */
+ ErrCode code; /**< Error code */
+ public:
+
+ SyntaxError(ErrCode code); /**< Construct an SyntaxError */
+ string get_msg(); /**< Get the error message */
+};
+
+class TokenError : public SyntaxError {
+ public:
+ TokenError(string token, ErrCode code); /**< Construct an TokenError */
+};
+
+class NormalError : public SyntaxError {
+ public:
+ NormalError(ErrCode code);
+};
+
+#endif
diff --git a/main.cpp b/main.cpp
index f32dac3..31d7943 100644
--- a/main.cpp
+++ b/main.cpp
@@ -2,6 +2,7 @@
#include "builtin.h"
#include "parser.h"
#include "eval.h"
+#include "exc.h"
#include <cstdio>
#ifdef DEBUG
@@ -15,6 +16,7 @@ void tree_print(Cons *ptr) {
#endif
int main() {
+ //freopen("in", "r", stdin);
Tokenizor *tk = new Tokenizor();
ASTGenerator *ast = new ASTGenerator();
Evaluator *eval = new Evaluator();
@@ -24,6 +26,13 @@ int main() {
Cons *tree = ast->absorb(tk);
if (!tree) break;
//tree_print(tree);
- printf("%s\n", eval->run_expr(tree)->ext_repr().c_str());
+ try
+ {
+ printf("%s\n", eval->run_expr(tree)->ext_repr().c_str());
+ }
+ catch (GeneralError &e)
+ {
+ printf("An error occured: %s\n", e.get_msg().c_str());
+ }
}
}
diff --git a/model.cpp b/model.cpp
index 9ecd5f7..d53a9bf 100644
--- a/model.cpp
+++ b/model.cpp
@@ -14,7 +14,7 @@ string EmptyList::_debug_repr() { return ext_repr(); }
#endif
bool FrameObj::is_ret_addr() {
- return ftype == CLS_RET_ADDR;
+ return ftype & CLS_RET_ADDR;
}
EvalObj::EvalObj(ClassType _otype) : FrameObj(CLS_EVAL_OBJ), otype(_otype) {}
@@ -22,7 +22,15 @@ EvalObj::EvalObj(ClassType _otype) : FrameObj(CLS_EVAL_OBJ), otype(_otype) {}
void EvalObj::prepare(Cons *pc) {}
bool EvalObj::is_simple_obj() {
- return otype == CLS_SIM_OBJ;
+ return otype & CLS_SIM_OBJ;
+}
+
+bool EvalObj::is_sym_obj() {
+ return otype & CLS_SYM_OBJ;
+}
+
+bool EvalObj::is_opt_obj() {
+ return otype & CLS_OPT_OBJ;
}
#ifdef DEBUG
@@ -70,7 +78,8 @@ string UnspecObj::ext_repr() { return string("#<Unspecified>"); }
string UnspecObj::_debug_repr() { return ext_repr(); }
#endif
-SymObj::SymObj(const string &str) : EvalObj(), val(str) {}
+SymObj::SymObj(const string &str) :
+ EvalObj(CLS_SIM_OBJ | CLS_SYM_OBJ), val(str) {}
string SymObj::ext_repr() { return "#<Symbol: " + val + ">"; }
@@ -78,7 +87,7 @@ string SymObj::ext_repr() { return "#<Symbol: " + val + ">"; }
string SymObj::_debug_repr() { return ext_repr(); }
#endif
-OptObj::OptObj() : EvalObj() {}
+OptObj::OptObj() : EvalObj(CLS_SIM_OBJ | CLS_OPT_OBJ) {}
ProcObj::ProcObj(ASTList *_body,
Environment *_envt,
@@ -141,8 +150,8 @@ bool Environment::add_binding(SymObj *sym_obj, EvalObj *eval_obj, bool def) {
}
EvalObj *Environment::get_obj(EvalObj *obj) {
- SymObj *sym_obj = dynamic_cast<SymObj*>(obj);
- if (!sym_obj) return obj; // Not a SymObj
+ if (!obj->is_sym_obj()) return obj;
+ SymObj *sym_obj = static_cast<SymObj*>(obj);
string name(sym_obj->val);
for (Environment *ptr = this; ptr; ptr = ptr->prev_envt)
diff --git a/model.h b/model.h
index ee0e8ae..ebae3d6 100644
--- a/model.h
+++ b/model.h
@@ -11,10 +11,13 @@ using std::map;
typedef unsigned char ClassType; // that range is enough
-static const int CLS_RET_ADDR = 0;
-static const int CLS_EVAL_OBJ = 1;
-static const int CLS_SIM_OBJ = 0;
-static const int CLS_CONS_OBJ = 1;
+static const int CLS_RET_ADDR = 1 << 0;
+static const int CLS_EVAL_OBJ = 1 << 1;
+
+static const int CLS_SIM_OBJ = 1 << 0;
+static const int CLS_CONS_OBJ = 1 << 1;
+static const int CLS_SYM_OBJ = 1 << 2;
+static const int CLS_OPT_OBJ = 1 << 3;
/** @class FrameObj
* Objects that can be held in the evaluation stack
@@ -69,7 +72,10 @@ class EvalObj : public FrameObj {
* @return true if the object is not a construction (Cons)
* */
bool is_simple_obj();
- /** External representation of this object */
+ /** Check if the object is a symobl */
+ bool is_sym_obj();
+ /** Check if the object is an operator */
+ bool is_opt_obj();
virtual void prepare(Cons *pc);
/** Any EvalObj has its external representation */
virtual string ext_repr() = 0;