diff options
author | Teddy <[email protected]> | 2013-08-05 19:49:31 +0800 |
---|---|---|
committer | Teddy <[email protected]> | 2013-08-05 19:49:31 +0800 |
commit | a6574b0025b68eb28a8c7d679ca6783132ad013d (patch) | |
tree | 09f8e9976e209c9e7bf48556e8d90f211c1b3464 | |
parent | 5dba94ed1eec7a808cab022a23480b4d39518307 (diff) |
complex, real, rational, integral number support
-rw-r--r-- | builtin.cpp | 425 | ||||
-rw-r--r-- | builtin.h | 151 | ||||
-rw-r--r-- | consts.cpp | 5 | ||||
-rw-r--r-- | consts.h | 5 | ||||
-rw-r--r-- | eval.cpp | 3 | ||||
-rw-r--r-- | exc.cpp | 12 | ||||
-rw-r--r-- | exc.h | 11 | ||||
-rw-r--r-- | model.cpp | 16 | ||||
-rw-r--r-- | model.h | 43 | ||||
-rw-r--r-- | parser.cpp | 23 | ||||
-rw-r--r-- | parser.h | 2 |
11 files changed, 526 insertions, 170 deletions
diff --git a/builtin.cpp b/builtin.cpp index 79ecdfb..6c58d96 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -1,46 +1,356 @@ #include "exc.h" #include "consts.h" #include "builtin.h" +#include "model.h" +#include "exc.h" #include <cstdio> #include <sstream> +#include <cctype> +#include <cstdlib> using std::stringstream; extern EmptyList *empty_list; +static const int NUM_LVL_COMP = 0; +static const int NUM_LVL_REAL = 1; +static const int NUM_LVL_RAT = 2; +static const int NUM_LVL_INT = 3; -BoolObj::BoolObj(bool _val) : EvalObj(), val(_val) {} - -bool BoolObj::is_true() { return val; } - -string BoolObj::ext_repr() { return string(val ? "#t" : "#f"); } - -#ifdef DEBUG -string BoolObj::_debug_repr() { return ext_repr(); } -#endif - -IntObj::IntObj(int _val) : NumberObj(), val(_val) {} -string IntObj::ext_repr() { +string double_to_str(double val, bool force_sign = false) { stringstream ss; + if (force_sign) ss << std::showpos; ss << val; return ss.str(); } -#ifdef DEBUG -string IntObj::_debug_repr() { return ext_repr(); } -#endif - -FloatObj::FloatObj(double _val) : NumberObj(), val(_val) {} - -string FloatObj::ext_repr() { +string int_to_str(int val) { stringstream ss; ss << val; return ss.str(); } -#ifdef DEBUG -string FloatObj::_debug_repr() { return ext_repr(); } -#endif +double str_to_double(string repr, bool &flag) { + const char *nptr = repr.c_str(); + char *endptr; + double val = strtod(nptr, &endptr); + if (endptr != nptr + repr.length()) + { + flag = false; + return 0; + } + flag = true; + return val; +} + +int gcd(int a, int b) { + int t; + while (b) t = b, b = a % b, a = t; + return a; +} + + +InexactNumObj::InexactNumObj(NumLvl level) : NumObj(level, false) {} + +CompNumObj::CompNumObj(double _real, double _imag) : + InexactNumObj(NUM_LVL_COMP), real(_real), imag(_imag) {} + +CompNumObj *CompNumObj::from_string(string repr) { + // spos: the position of the last sign + // ipos: the position of i + int spos = -1, ipos = -1, + len = repr.length(); + bool sign; + for (int i = 0; i < len; i++) + if (repr[i] == '+' || repr[i] == '-') + { + spos = i; + sign = repr[i] == '-'; + } + else if (repr[i] == 'i' || repr[i] == 'I') + ipos = i; + + if (spos == -1 || ipos == -1 || !(spos < ipos)) + return NULL; + + bool flag; + double real = 0, imag = 1; + if (spos > 0) + { + real = str_to_double(repr.substr(0, spos), flag); + if (!flag) return NULL; + } + if (ipos > spos + 1) + { + imag = str_to_double(repr.substr(spos + 1, ipos - spos - 1), flag); + if (!flag) return NULL; + } + if (sign) imag = -imag; + return new CompNumObj(real, imag); +} + +CompNumObj *CompNumObj::convert(NumObj *obj) { + switch (obj->level) + { + case NUM_LVL_COMP : + return static_cast<CompNumObj*>(obj); break; + case NUM_LVL_REAL : + return new CompNumObj(static_cast<RealNumObj*>(obj)->real, 0); + break; + case NUM_LVL_RAT : + { + RatNumObj *rat = static_cast<RatNumObj*>(obj); + return new CompNumObj(rat->a / double(rat->b), 0); + break; + } + case NUM_LVL_INT : + return new CompNumObj(static_cast<IntNumObj*>(obj)->val, 0); + } + throw NormalError(INT_ERR); +} + +#define A (real) +#define B (imag) +#define C (r->real) +#define D (r->imag) + +NumObj *CompNumObj::plus(NumObj *_r) { + CompNumObj *r = CompNumObj::convert(_r); + return new CompNumObj(A + C, B + D); +} + +NumObj *CompNumObj::minus(NumObj *_r) { + CompNumObj *r = CompNumObj::convert(_r); + return new CompNumObj(A - C, B - D); +} + +NumObj *CompNumObj::multi(NumObj *_r) { + CompNumObj *r = CompNumObj::convert(_r); + return new CompNumObj(A * C - B * D, + B * C + A * D); +} + +NumObj *CompNumObj::div(NumObj *_r) { + CompNumObj *r = CompNumObj::convert(_r); + double f = 1.0 / (C * C + D * D); + return new CompNumObj((A * C + B * D) * f, + (B * C - A * D) * f); +} + +BoolObj *CompNumObj::eq(NumObj *_r) { + CompNumObj *r = CompNumObj::convert(_r); + return new BoolObj(A == C && B == D); // TODO: more proper judgement +} + +string CompNumObj::ext_repr() { + return double_to_str(real) + double_to_str(imag, true) + "i"; +} + +#undef A +#undef B +#undef C +#undef D + +RealNumObj::RealNumObj(double _real) : InexactNumObj(NUM_LVL_REAL), real(_real) {} + +RealNumObj *RealNumObj::from_string(string repr) { + bool flag; + double real = str_to_double(repr, flag); + if (!flag) return NULL; + return new RealNumObj(real); +} + +RealNumObj *RealNumObj::convert(NumObj *obj) { + switch (obj->level) + { + case NUM_LVL_REAL: + return static_cast<RealNumObj*>(obj); break; + case NUM_LVL_RAT: + { + RatNumObj *rat = static_cast<RatNumObj*>(obj); + return new RealNumObj(rat->a / double(rat->b)); + break; + } + case NUM_LVL_INT: + return new RealNumObj(static_cast<IntNumObj*>(obj)->val); + } + throw NormalError(INT_ERR); +} + +NumObj *RealNumObj::plus(NumObj *_r) { + return new RealNumObj(real + RealNumObj::convert(_r)->real); +} + +NumObj *RealNumObj::minus(NumObj *_r) { + return new RealNumObj(real - RealNumObj::convert(_r)->real); +} + +NumObj *RealNumObj::multi(NumObj *_r) { + return new RealNumObj(real * RealNumObj::convert(_r)->real); +} + +NumObj *RealNumObj::div(NumObj *_r) { + return new RealNumObj(real / RealNumObj::convert(_r)->real); +} + +BoolObj *RealNumObj::eq(NumObj *_r) { + return new BoolObj(real == RealNumObj::convert(_r)->real); +} + +BoolObj *RealNumObj::lt(NumObj *_r) { + return new BoolObj(real < RealNumObj::convert(_r)->real); +} + +BoolObj *RealNumObj::gt(NumObj *_r) { + return new BoolObj(real > RealNumObj::convert(_r)->real); +} + +string RealNumObj::ext_repr() { + return double_to_str(real); +} + +ExactNumObj::ExactNumObj(NumLvl level) : NumObj(level, false) {} + +RatNumObj::RatNumObj(int _a, int _b) : + ExactNumObj(NUM_LVL_RAT), a(_a), b(_b) { + int g = gcd(a, b); + a /= g; + b /= g; +} + +RatNumObj *RatNumObj::from_string(string repr) { + int a, b; + if (sscanf(repr.c_str(), "%d/%d", &a, &b) != 2) + return NULL; + return new RatNumObj(a, b); +} + +RatNumObj *RatNumObj::convert(NumObj *obj) { + switch (obj->level) + { + case NUM_LVL_RAT: + return static_cast<RatNumObj*>(obj); break; + case NUM_LVL_INT: + return new RatNumObj(static_cast<IntNumObj*>(obj)->val, 1); + } + throw NormalError(INT_ERR); +} + +#define A (a) +#define B (b) +#define C (r->a) +#define D (r->b) + +NumObj *RatNumObj::plus(NumObj *_r) { + RatNumObj *r = RatNumObj::convert(_r); + int na = A * D + B * C, nb = B * D; + int g = gcd(na, nb); + na /= g; + nb /= g; + return new RatNumObj(na, nb); +} + +NumObj *RatNumObj::minus(NumObj *_r) { + RatNumObj *r = RatNumObj::convert(_r); + int na = A * D - B * C, nb = B * D; + int g = gcd(na, nb); + na /= g; + nb /= g; + return new RatNumObj(na, nb); +} + +NumObj *RatNumObj::multi(NumObj *_r) { + RatNumObj *r = RatNumObj::convert(_r); + int na = A * C, nb = B * D; + int g = gcd(na, nb); + na /= g; + nb /= g; + return new RatNumObj(na, nb); +} + +NumObj *RatNumObj::div(NumObj *_r) { + RatNumObj *r = RatNumObj::convert(_r); + int na = A * D, nb = B * C; + int g = gcd(na, nb); + na /= g; + nb /= g; + return new RatNumObj(na, nb); +} + +BoolObj *RatNumObj::lt(NumObj *_r) { + RatNumObj *r = RatNumObj::convert(_r); + return new BoolObj(A * D < C * B); +} + +BoolObj *RatNumObj::gt(NumObj *_r) { + RatNumObj *r = RatNumObj::convert(_r); + return new BoolObj(A * D > C * B); +} + +BoolObj *RatNumObj::eq(NumObj *_r) { + RatNumObj *r = RatNumObj::convert(_r); + return new BoolObj(A * D == C * B); +} + +string RatNumObj::ext_repr() { + return int_to_str(A) + "/" + int_to_str(B); +} + +IntNumObj::IntNumObj(int _val) : ExactNumObj(NUM_LVL_INT), val(_val) {} + +IntNumObj *IntNumObj::from_string(string repr) { + int val = 0; + for (int i = 0; i < repr.length(); i++) + { + if (!('0' <= repr[i] && repr[i] <= '9')) + return NULL; + val = val * 10 + repr[i] - '0'; + } + return new IntNumObj(val); +} + +IntNumObj *IntNumObj::convert(NumObj *obj) { + switch (obj->level) + { + case NUM_LVL_INT : + return static_cast<IntNumObj*>(obj); + default: + throw NormalError(INT_ERR); + } +} + +NumObj *IntNumObj::plus(NumObj *_r) { + + return new IntNumObj(val + IntNumObj::convert(_r)->val); +} + +NumObj *IntNumObj::minus(NumObj *_r) { + return new IntNumObj(val - IntNumObj::convert(_r)->val); +} + +NumObj *IntNumObj::multi(NumObj *_r) { + return new IntNumObj(val * IntNumObj::convert(_r)->val); +} + +NumObj *IntNumObj::div(NumObj *_r) { + return new IntNumObj(val / IntNumObj::convert(_r)->val); +} + +BoolObj *IntNumObj::lt(NumObj *_r) { + return new BoolObj(val < IntNumObj::convert(_r)->val); +} + +BoolObj *IntNumObj::gt(NumObj *_r) { + return new BoolObj(val > IntNumObj::convert(_r)->val); +} + +BoolObj *IntNumObj::eq(NumObj *_r) { + return new BoolObj(val == IntNumObj::convert(_r)->val); +} + +string IntNumObj::ext_repr() { + return int_to_str(val); +} SpecialOptIf::SpecialOptIf() : SpecialOptObj() {} @@ -113,10 +423,6 @@ Cons *SpecialOptIf::call(ArgList *args, Environment * &envt, string SpecialOptIf::ext_repr() { return string("#<Builtin Macro: if>"); } -#ifdef DEBUG -string SpecialOptIf::_debug_repr() { return ext_repr(); } -#endif - SpecialOptLambda::SpecialOptLambda() : SpecialOptObj() {} #define FILL_MARKS(pc, flag) \ for (Cons *ptr = TO_CONS(pc->cdr); \ @@ -155,10 +461,6 @@ Cons *SpecialOptLambda::call(ArgList *args, Environment * &envt, string SpecialOptLambda::ext_repr() { return string("#<Builtin Macro: lambda>"); } -#ifdef DEBUG -string SpecialOptLambda::_debug_repr() { return ext_repr(); } -#endif - SpecialOptDefine::SpecialOptDefine() : SpecialOptObj() {} void SpecialOptDefine::prepare(Cons *pc) { @@ -224,10 +526,6 @@ Cons *SpecialOptDefine::call(ArgList *args, Environment * &envt, string SpecialOptDefine::ext_repr() { return string("#<Builtin Macro: define>"); } -#ifdef DEBUG -string SpecialOptDefine::_debug_repr() { return ext_repr(); } -#endif - void SpecialOptSet::prepare(Cons *pc) { pc = TO_CONS(pc->cdr); if (pc == empty_list) @@ -263,10 +561,6 @@ SpecialOptSet::SpecialOptSet() {} string SpecialOptSet::ext_repr() { return string("#<Builtin Macro: set!>"); } -#ifdef DEBUG -string SpecialOptSet::_debug_repr() { return ext_repr(); } -#endif - EvalObj *builtin_cons(ArgList *args) { if (args == empty_list || args->cdr == empty_list || @@ -301,52 +595,21 @@ EvalObj *builtin_list(ArgList *args) { } EvalObj *builtin_plus(ArgList *args) { - // TODO: type conversion and proper arithmetic - int res = 0; - for (Cons *ptr = args; ptr != empty_list; ptr = TO_CONS(ptr->cdr)) - res += dynamic_cast<IntObj*>(ptr->car)->val; - return new IntObj(res); -} - -EvalObj *builtin_minus(ArgList *args) { - // TODO: type conversion and proper arithmetic - int res = dynamic_cast<IntObj*>(args->car)->val; - 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_times(ArgList *args) { - // TODO: type conversion and proper arithmetic - int res = 1; + NumObj *res = new IntNumObj(0), *opr; // the most accurate type for (Cons *ptr = args; ptr != empty_list; ptr = TO_CONS(ptr->cdr)) - res *= dynamic_cast<IntObj*>(ptr->car)->val; - return new IntObj(res); -} - -EvalObj *builtin_div(ArgList *args) { - // TODO: type conversion and proper arithmetic - int res = dynamic_cast<IntObj*>(args->car)->val; - 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*>(TO_CONS(args->cdr)->car)->val); -} - -EvalObj *builtin_gt(ArgList *args) { - return new BoolObj(dynamic_cast<IntObj*>(args->car)->val > - dynamic_cast<IntObj*>(TO_CONS(args->cdr)->car)->val); + { + if (!ptr->car->is_num_obj()) // not a number + throw TokenError(ptr->car->ext_repr(), RUN_ERR_WRONG_TYPE); + opr = static_cast<NumObj*>(ptr->car); + if (res->level < opr->level) + // upper type conversion + res = res->plus(opr); + else + res = opr->plus(res); + } + return res; } -EvalObj *builtin_arithmetic_eq(ArgList *args) { - return new BoolObj(dynamic_cast<IntObj*>(args->car)->val == - dynamic_cast<IntObj*>(TO_CONS(args->cdr)->car)->val); -} EvalObj *builtin_display(ArgList *args) { printf("%s\n", args->car->ext_repr().c_str()); @@ -6,46 +6,122 @@ using std::string; -/** @class BoolObj - * Booleans + + +/** @class InexactNumObj + * Inexact number implementation (using doubles) */ -class BoolObj: public EvalObj { +class InexactNumObj: public NumObj { public: - bool val; /**< true for \#t, false for \#f */ - BoolObj(bool); /**< Converts a C bool value to a BoolObj*/ - bool is_true(); /**< Override EvalObj `is_true()` */ -#ifdef DEBUG - string _debug_repr(); -#endif + InexactNumObj(NumLvl level); +}; + +/** @class CompNumObj + * Complex numbers + */ +class CompNumObj: public InexactNumObj { + public: + double real, imag; + + /** Construct a complex number */ + CompNumObj(double _real, double _imag); + /** Try to construct an RealNumObj object + * @return NULL if failed + */ + static CompNumObj *from_string(string repr); + /** Convert to a complex number from other numeric types */ + static CompNumObj *convert(NumObj* obj); + + NumObj *plus(NumObj *r); + NumObj *minus(NumObj *r); + NumObj *multi(NumObj *r); + NumObj *div(NumObj *r); + BoolObj *eq(NumObj *r); string ext_repr(); }; -/** @class IntObj - * A simple implementation of integers - * Will be removed in the future +/** @class RealNumObj + * Real numbers */ -class IntObj: public NumberObj { +class RealNumObj: public InexactNumObj { public: - int val; /**< Numeric value */ - /** Converts a C integer value to a FloatObj */ - IntObj(int); -#ifdef DEBUG - string _debug_repr(); -#endif + double real; + /** Construct a real number */ + RealNumObj(double _real); + /** Try to construct an RealNumObj object + * @return NULL if failed + */ + static RealNumObj *from_string(string repr); + /** Convert to a real number from other numeric types */ + static RealNumObj *convert(NumObj* obj); + + NumObj *plus(NumObj *r); + NumObj *minus(NumObj *r); + NumObj *multi(NumObj *r); + NumObj *div(NumObj *r); + BoolObj *lt(NumObj *r); + BoolObj *gt(NumObj *r); + BoolObj *eq(NumObj *r); string ext_repr(); + }; -/** @class FloatObj - * Floating point numbers + +/** @class ExactNumObj + * Exact number implementation (using gmp) */ -class FloatObj: public NumberObj { +class ExactNumObj: public NumObj { public: - double val; /**< Numeric value */ - /** Converts a C double value to a FloatObj */ - FloatObj(double); -#ifdef DEBUG - string _debug_repr(); -#endif + ExactNumObj(NumLvl level); +}; + +/** @class RatNumObj + * Rational numbers + */ +class RatNumObj: public ExactNumObj { + public: + int a, b; + /** Construct a rational number */ + RatNumObj(int _a, int _b); + /** Try to construct an RealNumObj object + * @return NULL if failed + */ + static RatNumObj *from_string(string repr); + /** Convert to a Rational number from other numeric types */ + static RatNumObj *convert(NumObj* obj); + + NumObj *plus(NumObj *r); + NumObj *minus(NumObj *r); + NumObj *multi(NumObj *r); + NumObj *div(NumObj *r); + BoolObj *lt(NumObj *r); + BoolObj *gt(NumObj *r); + BoolObj *eq(NumObj *r); + string ext_repr(); +}; + +/** @class IntNumObj + * Integers + */ +class IntNumObj: public ExactNumObj { + public: + int val; + /** Construct a integer */ + IntNumObj(int _val); + /** Try to construct an IntNumObj object + * @return NULL if failed + */ + static IntNumObj *from_string(string repr); + /** Convert to a integer from other numeric types */ + static IntNumObj *convert(NumObj* obj); + + NumObj *plus(NumObj *r); + NumObj *minus(NumObj *r); + NumObj *multi(NumObj *r); + NumObj *div(NumObj *r); + BoolObj *lt(NumObj *r); + BoolObj *gt(NumObj *r); + BoolObj *eq(NumObj *r); string ext_repr(); }; @@ -73,9 +149,6 @@ class SpecialOptIf: public SpecialOptObj { void prepare(Cons *pc); Cons *call(ArgList *args, Environment * &envt, Continuation * &cont, FrameObj ** &top_ptr); -#ifdef DEBUG - string _debug_repr(); -#endif string ext_repr(); }; @@ -89,9 +162,6 @@ class SpecialOptLambda: public SpecialOptObj { Cons *call(ArgList *args, Environment * &envt, Continuation * &cont, FrameObj ** &top_ptr); -#ifdef DEBUG - string _debug_repr(); -#endif string ext_repr(); }; @@ -104,9 +174,6 @@ class SpecialOptDefine: public SpecialOptObj { void prepare(Cons *pc); Cons *call(ArgList *args, Environment * &envt, Continuation * &cont, FrameObj ** &top_ptr); -#ifdef DEBUG - string _debug_repr(); -#endif string ext_repr(); }; @@ -119,19 +186,11 @@ class SpecialOptSet: public SpecialOptObj { void prepare(Cons *pc); Cons *call(ArgList *args, Environment * &envt, Continuation * &cont, FrameObj ** &top_ptr); -#ifdef DEBUG - string _debug_repr(); -#endif string ext_repr(); }; EvalObj *builtin_plus(ArgList *); -EvalObj *builtin_minus(ArgList *); -EvalObj *builtin_times(ArgList *); -EvalObj *builtin_div(ArgList *); -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 *); @@ -1,6 +1,6 @@ #include "consts.h" -const char *SYN_ERR_MSG[] = { +const char *ERR_MSG[] = { "\"%s\" is not an valid identifier", "Cannot apply the operation \"%s\"", "Unbound variable: \"%s\"", @@ -9,5 +9,6 @@ const char *SYN_ERR_MSG[] = { "Wrong number of arguments to procedure (%s)", "Illegal empty combination ()", "Unexpected \")\"", - "Wrong type (expecting %s)" + "Wrong type (expecting %s)", + "Internal Error !!! File a bug please!" }; @@ -10,9 +10,10 @@ enum ErrCode { RUN_ERR_WRONG_NUM_OF_ARGS, SYN_ERR_EMPTY_COMB, READ_ERR_UNEXPECTED_RIGHT_BRACKET, - RUN_ERR_WRONG_TYPE + RUN_ERR_WRONG_TYPE, + INT_ERR }; -extern const char *SYN_ERR_MSG[]; +extern const char *ERR_MSG[]; #endif @@ -14,12 +14,13 @@ void Evaluator::add_builtin_routines() { envt->add_binding(new SymObj(name), rout) ADD_ENTRY("+", new BuiltinProcObj(builtin_plus, "+")); - ADD_ENTRY("-", new BuiltinProcObj(builtin_minus, "-")); +/* ADD_ENTRY("-", new BuiltinProcObj(builtin_minus, "-")); ADD_ENTRY("*", new BuiltinProcObj(builtin_times, "*")); ADD_ENTRY("/", new BuiltinProcObj(builtin_div, "/")); ADD_ENTRY(">", new BuiltinProcObj(builtin_gt, ">")); 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")); @@ -1,16 +1,16 @@ #include "exc.h" #include <cstdio> -SyntaxError::SyntaxError(ErrCode _code) : code(_code) {} +GeneralError::GeneralError(ErrCode _code) : code(_code) {} -string SyntaxError::get_msg() { return this->msg; } +string GeneralError::get_msg() { return this->msg; } -TokenError::TokenError(string token, ErrCode code) : SyntaxError(code) { +TokenError::TokenError(string token, ErrCode code) : GeneralError(code) { static char buffer[1024]; // should be enough - sprintf(buffer, SYN_ERR_MSG[code], token.c_str()); + sprintf(buffer, ERR_MSG[code], token.c_str()); msg = buffer; } -NormalError::NormalError(ErrCode code) : SyntaxError(code) { - msg = SYN_ERR_MSG[code]; +NormalError::NormalError(ErrCode code) : GeneralError(code) { + msg = ERR_MSG[code]; } @@ -10,26 +10,21 @@ using std::string; * 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 */ + GeneralError(ErrCode code); /**< Construct a General Error */ string get_msg(); /**< Get the error message */ }; -class TokenError : public SyntaxError { +class TokenError : public GeneralError { public: TokenError(string token, ErrCode code); /**< Construct an TokenError */ }; -class NormalError : public SyntaxError { +class NormalError : public GeneralError { public: NormalError(ErrCode code); }; @@ -39,7 +39,14 @@ bool EvalObj::is_cons_obj() { return otype & CLS_CONS_OBJ; } +bool EvalObj::is_num_obj() { + return otype & CLS_NUM_OBJ; +} + #ifdef DEBUG +string EvalObj::_debug_repr() { + return ext_repr(); +} void EvalObj::_debug_print() { printf("mem: 0x%llX\n%s\n\n", (unsigned long long)this, _debug_repr().c_str()); @@ -143,7 +150,14 @@ string ProcObj::_debug_repr() { return ext_repr(); } SpecialOptObj::SpecialOptObj() : OptObj() {} -NumberObj::NumberObj() : EvalObj() {} +BoolObj::BoolObj(bool _val) : EvalObj(), val(_val) {} + +bool BoolObj::is_true() { return val; } + +string BoolObj::ext_repr() { return string(val ? "#t" : "#f"); } + +NumObj::NumObj(NumLvl _level, bool _exactness) : + EvalObj(CLS_SIM_OBJ | CLS_NUM_OBJ), level(_level), exactness(_exactness) {} BuiltinProcObj::BuiltinProcObj(BuiltinProc f, string _name) : OptObj(), handler(f), name(_name) {} @@ -9,7 +9,9 @@ using std::list; using std::string; using std::map; -typedef unsigned char ClassType; // that range is enough +// the range of unsigned char is enough for these types +typedef unsigned char ClassType; +typedef unsigned char NumLvl; static const int CLS_RET_ADDR = 1 << 0; static const int CLS_EVAL_OBJ = 1 << 1; @@ -18,6 +20,8 @@ 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; +static const int CLS_NUM_OBJ = 1 << 4; + #define TO_CONS(ptr) \ (static_cast<Cons*>(ptr)) @@ -81,12 +85,15 @@ class EvalObj : public FrameObj { bool is_opt_obj(); /** Check if the object is a Cons */ bool is_cons_obj(); + /** Check if the object is a number */ + bool is_num_obj(); virtual void prepare(Cons *pc); /** Any EvalObj has its external representation */ virtual string ext_repr() = 0; /** Always true for all EvalObjs except BoolObj */ virtual bool is_true(); #ifdef DEBUG + virtual string _debug_repr(); virtual void _debug_print(); #endif }; @@ -243,13 +250,41 @@ class BuiltinProcObj: public OptObj { string ext_repr(); }; -/** @class NumberObj +/** @class BoolObj + * Booleans + */ +class BoolObj: public EvalObj { + public: + bool val; /**< true for \#t, false for \#f */ + BoolObj(bool); /**< Converts a C bool value to a BoolObj*/ + bool is_true(); /**< Override EvalObj `is_true()` */ + string ext_repr(); +}; + +/** @class NumObj * The top level abstract of numbers */ -class NumberObj: public EvalObj { +class NumObj: public EvalObj { + protected: + /** True if the number is of exact value */ + bool exactness; public: - NumberObj(); + /** The level of the specific number. The smaller the level + * is, the more generic that number is. + */ + NumLvl level; + + /** + * Construct a general Numeric object + */ + NumObj(NumLvl level, bool _exactness); + bool is_exact(); + virtual NumObj *plus(NumObj *r) = 0; + virtual NumObj *minus(NumObj *r) = 0; + virtual NumObj *multi(NumObj *r) = 0; + virtual NumObj *div(NumObj *r) = 0; + virtual BoolObj *eq(NumObj *r) = 0; }; typedef map<string, EvalObj*> Str2EvalObj; @@ -64,28 +64,17 @@ bool Tokenizor::get_token(string &ret) { } ASTGenerator::ASTGenerator() {} -EvalObj *ASTGenerator::to_float(const string &str) { - stringstream ss(str); - double val; - ss >> val; - if (ss.fail() || !ss.eof()) return NULL; - return new FloatObj(val); -} - -EvalObj *ASTGenerator::to_int(const string &str) { - stringstream ss(str); - int val; - ss >> val; - if (ss.fail() || !ss.eof()) return NULL; - return new IntObj(val); -} EvalObj *ASTGenerator::to_obj(const string &str) { EvalObj *res = NULL; - if ((res = ASTGenerator::to_int(str))) + if ((res = IntNumObj::from_string(str))) + return res; + if ((res = RatNumObj::from_string(str))) + return res; + if ((res = RealNumObj::from_string(str))) return res; - if ((res = ASTGenerator::to_float(str))) + if ((res = CompNumObj::from_string(str))) return res; return new SymObj(str); } @@ -34,8 +34,6 @@ class Tokenizor { */ class ASTGenerator { private: - static EvalObj* to_float(const string &); - static EvalObj* to_int(const string &); /** Convert the string to an internal object */ static EvalObj* to_obj(const string &); public: |