From 65f17438de5983ca010e10b4b24c5da65756a9b5 Mon Sep 17 00:00:00 2001 From: Teddy Date: Sun, 4 Aug 2013 11:50:41 +0800 Subject: added exception facilities --- Makefile | 2 +- builtin.cpp | 29 +++++++++++++++++++++++------ consts.cpp | 8 ++++++++ consts.h | 13 +++++++++++++ eval.cpp | 11 ++++++++++- exc.cpp | 16 ++++++++++++++++ exc.h | 37 +++++++++++++++++++++++++++++++++++++ main.cpp | 11 ++++++++++- model.cpp | 21 +++++++++++++++------ model.h | 16 +++++++++++----- 10 files changed, 144 insertions(+), 20 deletions(-) create mode 100644 consts.cpp create mode 100644 consts.h create mode 100644 exc.cpp create mode 100644 exc.h 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 #include @@ -120,7 +122,7 @@ Cons *SpecialOptLambda::call(ArgList *args, Environment * &envt, Continuation * &cont, FrameObj ** &top_ptr) { Cons *ret_addr = static_cast(*top_ptr)->addr; Cons *pc = static_cast(ret_addr->car); - SymbolList *para_list = dynamic_cast(pc->cdr->car); // parameter list + SymbolList *para_list = static_cast(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(pc->cdr->car); + if (!first->is_sym_obj()) + throw TokenError(first->ext_repr(), SYN_ERR_NOT_AN_ID); + + id = static_cast(first); obj = args->cdr->car; } else { // static_cast because of is_simple_obj() is false Cons *plst = static_cast(pc->cdr->car); - id = dynamic_cast(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(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(*top_ptr)->addr; Cons *pc = static_cast(ret_addr->car); - SymObj *id = dynamic_cast(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(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 extern Cons *empty_list; @@ -87,7 +89,14 @@ EvalObj *Evaluator::run_expr(Cons *prog) { top_ptr++; } else - pc = dynamic_cast(args->car)->call(args, envt, cont, top_ptr); + { + EvalObj *opt = args->car; + if (opt->is_opt_obj()) + pc = static_cast(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 + +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 + +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 #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("#"); } 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 "#"; } @@ -78,7 +87,7 @@ string SymObj::ext_repr() { return "#"; } 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(obj); - if (!sym_obj) return obj; // Not a SymObj + if (!obj->is_sym_obj()) return obj; + SymObj *sym_obj = static_cast(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; -- cgit v1.2.3-70-g09d2