diff --git a/Makefile b/Makefile index 4a09afc..b8d3250 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,9 @@ CXXSTD := c++14 -CXXFLAGS := -std=$(CXXSTD) -Wall -Werror -g -O0 +CXXFLAGS := -std=$(CXXSTD) -Wall -Werror -Os -static +LDFLAGS := -static OBJS := linux/io.o \ io.o \ + system.o \ parser.o \ word.o \ dict.o \ @@ -11,7 +13,8 @@ TARGET := kforth all: $(TARGET) $(TARGET): $(OBJS) - $(CXX) $(CFLAGS) -o $@ $(OBJS) + $(CXX) $(CXXFLAGS) -o $@ $(OBJS) + strip $@ clean: rm -f $(OBJS) $(TARGET) diff --git a/defs.h b/defs.h index e070d27..8dff6ad 100644 --- a/defs.h +++ b/defs.h @@ -5,6 +5,7 @@ #include "linux/defs.h" #else typedef int KF_INT; +typedef long KF_LONG; constexpr uint8_t STACK_SIZE = 16; #endif diff --git a/dict.cc b/dict.cc index 96f18b7..a6a173f 100644 --- a/dict.cc +++ b/dict.cc @@ -4,23 +4,87 @@ #include "system.h" #include "word.h" +#include #include +constexpr size_t dshift = (sizeof(KF_INT) * 8) - 1; + +static bool +pop_long(System *sys, KF_LONG *d) +{ + KF_INT a = 0; + KF_INT b = 0; + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + *d = a << dshift; + *d += b; + sys->status = STATUS_OK; + return true; +} + +static inline KF_INT +mask(size_t bits) +{ + KF_INT m = 0; + + for (size_t i = 0; i < bits; i++) { + m += 1 << i; + } + + return m; +} + +static bool +push_long(System *sys, KF_LONG d) +{ + KF_INT a = static_cast((d >> dshift) & mask(dshift)); + KF_INT b = static_cast(d & mask(dshift)); + + if (!sys->dstack.push(b)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + static bool add(System *sys) { KF_INT a = 0; KF_INT b = 0; if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; return false; } if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; return false; } a += b; - return sys->dstack.push(a); + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; } static bool @@ -29,15 +93,23 @@ sub(System *sys) KF_INT a = 0; KF_INT b = 0; if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; return false; } if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; return false; } b -= a; - return sys->dstack.push(b); + if (!sys->dstack.push(b)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; } static bool @@ -45,16 +117,25 @@ mul(System *sys) { KF_INT a = 0; KF_INT b = 0; + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; return false; } if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; return false; } b *= a; - return sys->dstack.push(b); + if (!sys->dstack.push(b)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; } static bool @@ -63,15 +144,23 @@ div(System *sys) KF_INT a = 0; KF_INT b = 0; if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; return false; } if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; return false; } b /= a; - return sys->dstack.push(b); + if (!sys->dstack.push(b)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; } static bool @@ -80,18 +169,27 @@ swap(System *sys) KF_INT a = 0; KF_INT b = 0; if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; return false; } if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; return false; } if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; return false; } - return sys->dstack.push(b); + if (!sys->dstack.push(b)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; } static bool @@ -100,27 +198,39 @@ rot(System *sys) KF_INT a = 0; KF_INT b = 0; KF_INT c = 0; + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; return false; } if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; return false; } if (!sys->dstack.pop(&c)) { + sys->status = STATUS_STACK_UNDERFLOW; return false; } if (!sys->dstack.push(b)) { + sys->status = STATUS_STACK_OVERFLOW; return false; } if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; return false; } - return sys->dstack.push(c); + if (!sys->dstack.push(c)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; } // TODO: print multiple per line @@ -161,6 +271,755 @@ definitions(System *sys) } sys->interface->wrln(line, linelen); + sys->status = STATUS_OK; + return true; +} + +static bool +bye(System *sys) +{ + exit(0); + return true; +} + +static bool +dup(System *sys) +{ + KF_INT a; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +drop(System *sys) +{ + KF_INT a; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +dotess(System *sys) +{ + write_dstack(sys->interface, sys->dstack); + sys->interface->newline(); + sys->status = STATUS_OK; + return true; +} + +static bool +dot(System *sys) +{ + KF_INT a; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + write_num(sys->interface, a); + sys->interface->newline(); + sys->status = STATUS_OK; + return true; +} + +static bool +depth(System *sys) +{ + KF_INT a = static_cast(sys->dstack.size()); + + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +times_divide(System *sys) +{ + KF_INT a, b, c; + KF_LONG z; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.pop(&c)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + z = static_cast(c) * static_cast(b); + z /= static_cast(a); + a = static_cast(z); + + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +times_divide_mod(System *sys) +{ + KF_INT a, b, c; + KF_LONG y, z; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.pop(&c)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + z = static_cast(c) * static_cast(b); + y = z % static_cast(a); + z /= static_cast(a); + a = static_cast(z); + b = static_cast(y); + + if (!sys->dstack.push(b)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +divide_mod(System *sys) +{ + KF_INT a, b; + KF_INT y, z; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + + z = b / a; + y = b % a; + + if (!sys->dstack.push(y)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + if (!sys->dstack.push(z)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + + +/* +static bool +store(System *sys) +{ + KF_INT a = 0; // address + KF_INT b = 0; // value + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + KF_INT *p = (KF_INT *)(a); + *p = b; + + sys->status = STATUS_OK; + return true; +} + +static bool +plus_store(System *sys) +{ + KF_INT a = 0; // address + KF_INT b = 0; // value + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + KF_INT *p = (KF_INT *)(a); + *p += b; + + sys->status = STATUS_OK; + return true; +} +*/ + +static bool +zero_less(System *sys) +{ + KF_INT a; + bool ok; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (a < 0) { + ok = sys->dstack.push(-1); + } + else { + ok = sys->dstack.push(0); + } + + if (!ok) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +zero_equals(System *sys) +{ + KF_INT a; + bool ok; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (a == 0) { + ok = sys->dstack.push(-1); + } + else { + ok = sys->dstack.push(0); + } + + if (!ok) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +zero_greater(System *sys) +{ + KF_INT a; + bool ok; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (a > 0) { + ok = sys->dstack.push(-1); + } + else { + ok = sys->dstack.push(0); + } + + if (!ok) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +one_plus(System *sys) +{ + KF_INT a; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + a++; + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +one_minus(System *sys) +{ + KF_INT a; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + a--; + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +two_plus(System *sys) +{ + KF_INT a; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + a += 2; + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +two_minus(System *sys) +{ + KF_INT a; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + a -= 2; + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +two_divide(System *sys) +{ + KF_INT a; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + a >>= 1; + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +less_than(System *sys) +{ + KF_INT a, b; + bool ok; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (b < a) { + ok = sys->dstack.push(-1); + } + else { + ok = sys->dstack.push(0); + } + + if (!ok) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +equals(System *sys) +{ + KF_INT a, b; + bool ok; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (b == a) { + ok = sys->dstack.push(-1); + } + else { + ok = sys->dstack.push(0); + } + + if (!ok) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +greater_than(System *sys) +{ + KF_INT a, b; + bool ok; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (b > a) { + ok = sys->dstack.push(-1); + } + else { + ok = sys->dstack.push(0); + } + + if (!ok) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +question_dupe(System *sys) +{ + KF_INT a; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + if (a != 0) { + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + } + + sys->status = STATUS_OK; + return true; +} + +static bool +absolute(System *sys) +{ + KF_INT a; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (a < 0) { + if (!sys->dstack.push(-a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + } + else { + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + } + + sys->status = STATUS_OK; + return true; +} + +static bool +land(System *sys) +{ + KF_INT a, b; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + a &= b; + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +lor(System *sys) +{ + KF_INT a, b; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.pop(&b)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + a |= b; + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +roll(System *sys) +{ + KF_INT a, b; + size_t i; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + i = sys->dstack.size() - static_cast(a) - 1; + if (!sys->dstack.remove(i, &b)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.push(b)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +over(System *sys) +{ + KF_INT a; + size_t i = sys->dstack.size() - 2; + + if (!sys->dstack.get(i, a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +dplus(System *sys) +{ + KF_LONG da, db; + + if (!pop_long(sys, &da)) { + // Status is already set. + return false; + } + + if (!pop_long(sys, &db)) { + // Status is already set. + return false; + } + + da += db; + + if (!push_long(sys, da)) { + // Status is already set. + return false; + } + + // Status is already set. + return true; +} + +static bool +dlt(System *sys) +{ + KF_LONG da, db; + bool ok; + + if (!pop_long(sys, &da)) { + // Status is already set. + return false; + } + + if (!pop_long(sys, &db)) { + // Status is already set. + return false; + } + + if (db < da) { + ok = sys->dstack.push(-1); + } + else { + ok = sys->dstack.push(0); + } + + if (!ok) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; + return true; +} + +static bool +negate(System *sys) +{ + KF_INT a; + + if (!sys->dstack.pop(&a)) { + sys->status = STATUS_STACK_UNDERFLOW; + return false; + } + + a = ~a; + a++; + + if (!sys->dstack.push(a)) { + sys->status = STATUS_STACK_OVERFLOW; + return false; + } + + sys->status = STATUS_OK; return true; } @@ -168,17 +1027,47 @@ void init_dict(System *sys) { sys->dict = nullptr; - sys->dict = new Builtin((const char *)"DEFINITIONS", 11, sys->dict, definitions); - sys->dict = new Builtin((const char *)"+", 1, sys->dict, add); - sys->dict = new Builtin((const char *)"-", 1, sys->dict, sub); - sys->dict = new Builtin((const char *)"*", 1, sys->dict, mul); - sys->dict = new Builtin((const char *)"/", 1, sys->dict, div); sys->dict = new Builtin((const char *)"SWAP", 4, sys->dict, swap); sys->dict = new Builtin((const char *)"ROT", 3, sys->dict, rot); + sys->dict = new Builtin((const char *)"ROLL", 4, sys->dict, roll); + sys->dict = new Builtin((const char *)"OVER", 4, sys->dict, over); + sys->dict = new Builtin((const char *)"NEGATE", 6, sys->dict, negate); + sys->dict = new Builtin((const char *)"OR", 2, sys->dict, lor); + sys->dict = new Builtin((const char *)"DUP", 3, sys->dict, dup); + sys->dict = new Builtin((const char *)"DROP", 4, sys->dict, drop); + sys->dict = new Builtin((const char *)"DEPTH", 5, sys->dict, depth); + sys->dict = new Builtin((const char *)"DEFINITIONS", 11, sys->dict, definitions); + sys->dict = new Builtin((const char *)"D<", 2, sys->dict, dlt); + sys->dict = new Builtin((const char *)"D+", 2, sys->dict, dplus); + sys->dict = new Builtin((const char *)"BYE", 3, sys->dict, bye); + sys->dict = new Builtin((const char *)"ABS", 3, sys->dict, absolute); + sys->dict = new Builtin((const char *)"AND", 3, sys->dict, land); + sys->dict = new Builtin((const char *)"?DUP", 4, sys->dict, question_dupe); + sys->dict = new Builtin((const char *)">", 1, sys->dict, greater_than); + sys->dict = new Builtin((const char *)"=", 1, sys->dict, equals); + sys->dict = new Builtin((const char *)"<", 1, sys->dict, less_than); + sys->dict = new Builtin((const char *)"2/", 2, sys->dict, two_divide); + sys->dict = new Builtin((const char *)"2-", 2, sys->dict, two_minus); + sys->dict = new Builtin((const char *)"2+", 2, sys->dict, two_plus); + sys->dict = new Builtin((const char *)"1-", 2, sys->dict, one_minus); + sys->dict = new Builtin((const char *)"1+", 2, sys->dict, one_plus); + sys->dict = new Builtin((const char *)"0>", 2, sys->dict, zero_greater); + sys->dict = new Builtin((const char *)"0=", 2, sys->dict, zero_equals); + sys->dict = new Builtin((const char *)"0<", 2, sys->dict, zero_less); + sys->dict = new Builtin((const char *)"*/MOD", 5, sys->dict, times_divide_mod); + sys->dict = new Builtin((const char *)"*/", 2, sys->dict, times_divide); + sys->dict = new Builtin((const char *)"/MOD", 4, sys->dict, divide_mod); + sys->dict = new Builtin((const char *)"/", 1, sys->dict, div); + sys->dict = new Builtin((const char *)".S", 2, sys->dict, dotess); + sys->dict = new Builtin((const char *)".", 1, sys->dict, dot); + sys->dict = new Builtin((const char *)"-", 1, sys->dict, sub); + // sys->dict = new Builtin((const char *)"+!", 2, sys->dict, plus_store); + sys->dict = new Builtin((const char *)"+", 1, sys->dict, add); + sys->dict = new Builtin((const char *)"*", 1, sys->dict, mul); + // sys->dict = new Builtin((const char *)"!", 1, sys->dict, store); } - -LOOKUP +bool lookup(struct Token *token, System *sys) { Word *cursor = sys->dict; @@ -186,20 +1075,39 @@ lookup(struct Token *token, System *sys) if (parse_num(token, &n)) { if (sys->dstack.push(n)) { - return LOOKUP_OK; + sys->status = STATUS_OK; + return true; } - return LOOKUP_FAILED; + sys->status = STATUS_STACK_OVERFLOW; + return false; } while (cursor != nullptr) { if (cursor->match(token)) { - if (cursor->eval(sys)) { - return LOOKUP_OK; + if (!cursor->eval(sys)) { + sys->dstack.clear(); + return false; } - return LOOKUP_FAILED; + return true; } cursor = cursor->next(); } - return LOOKUP_NOTFOUND; -} \ No newline at end of file + sys->status = STATUS_UNKNOWN_WORD; + return false; +} + +void +reset_system(System *sys) +{ + sys->status = STATUS_OK; + sys->dstack.clear(); + + auto cursor = sys->dict; + auto next = cursor; + while (cursor != nullptr) { + next = cursor->next(); + delete cursor; + cursor = next; + } +} diff --git a/dict.h b/dict.h index e9b5677..9085492 100644 --- a/dict.h +++ b/dict.h @@ -6,14 +6,9 @@ #include "system.h" #include "word.h" -typedef enum _LOOKUP_ : uint8_t { - LOOKUP_OK = 0, // Lookup executed properly. - LOOKUP_NOTFOUND = 1, // The token isn't in the dictionary. - LOOKUP_FAILED = 2 // The word failed to execute. -} LOOKUP; - void init_dict(System *); -LOOKUP lookup(struct Token *, System *); +void reset_system(System *); +bool lookup(struct Token *, System *); diff --git a/doc/part-0x05.rst b/doc/part-0x05.rst index 8cc5d5b..b3decf2 100644 --- a/doc/part-0x05.rst +++ b/doc/part-0x05.rst @@ -1,7 +1,7 @@ Write You a Forth, 0x05 ----------------------- -:date: 2018-02-24 12:23 +:date: 2018-02-27 08:06 :tags: wyaf, forth NB: Today's update was pretty large, so I don't show all of the code; this is diff --git a/io.cc b/io.cc index a86156b..bdb27cc 100644 --- a/io.cc +++ b/io.cc @@ -8,21 +8,12 @@ static constexpr size_t nbuflen = 11; void write_num(IO *interface, KF_INT n) { - - // TODO(kyle): make the size of the buffer depend on the size of - // KF_INT. char buf[nbuflen]; - uint8_t i = nbuflen; - memset(buf, 0, i); - bool neg = n < 0; + uint8_t i = nbuflen - 1; + memset(buf, 0, nbuflen); if (n < 0) { interface->wrch('-'); - n = ~n; - if (n == 0) { - neg = false; - n++; - } } else if (n == 0) { interface->wrch('0'); @@ -30,13 +21,28 @@ write_num(IO *interface, KF_INT n) } while (n != 0) { - char ch = (n % 10) + '0'; - if (neg && (i == nbuflen)) ch++; - buf[i-1] = ch; - i--; + char x = n % 10; + x = x < 0 ? -x : x; + x += '0'; + buf[i--] = x; n /= 10; } - uint8_t buflen = nbuflen - i % nbuflen; - interface->wrbuf(buf+i, buflen); -} \ No newline at end of file + interface->wrbuf(buf+i, nbuflen - i); +} + +void +write_dstack(IO *interface, Stack dstack) +{ + KF_INT tmp; + interface->wrch('<'); + for (size_t i = 0; i < dstack.size(); i++) { + if (i > 0) { + interface->wrch(' '); + } + + dstack.get(i, tmp); + write_num(interface, tmp); + } + interface->wrch('>'); +} diff --git a/io.h b/io.h index 38bf51b..8604546 100644 --- a/io.h +++ b/io.h @@ -2,6 +2,7 @@ #define __KF_IO_H__ #include "defs.h" +#include "stack.h" class IO { public: @@ -19,9 +20,12 @@ public: // Line I/O virtual bool rdln(char *buf, size_t len, size_t *readlen) = 0; virtual void wrln(char *buf, size_t len) = 0; + + virtual void newline(void) = 0; }; void write_num(IO *, KF_INT); +void write_dstack(IO *, Stack); #endif // __KF_IO_H__ \ No newline at end of file diff --git a/kforth.cc b/kforth.cc index 565b5b0..73cc528 100644 --- a/kforth.cc +++ b/kforth.cc @@ -10,25 +10,10 @@ #include "linux.h" #endif // __linux__ -static char ok[] = "ok.\n"; static System sys; - - -static void -write_dstack() -{ - KF_INT tmp; - sys.interface->wrch('<'); - for (size_t i = 0; i < sys.dstack.size(); i++) { - if (i > 0) { - sys.interface->wrch(' '); - } - - sys.dstack.get(i, tmp); - write_num(sys.interface, tmp); - } - sys.interface->wrch('>'); -} +#ifndef TRACE_STACK +#define TRACE_STACK false +#endif static bool parser(const char *buf, const size_t buflen) @@ -36,8 +21,6 @@ parser(const char *buf, const size_t buflen) static size_t offset = 0; static struct Token token; static PARSE_RESULT result = PARSE_FAIL; - static LOOKUP lresult = LOOKUP_FAILED; - static bool stop = false; offset = 0; @@ -46,34 +29,17 @@ parser(const char *buf, const size_t buflen) token.length = 0; while ((result = parse_next(buf, buflen, &offset, &token)) == PARSE_OK) { - lresult = lookup(&token, &sys); - switch (lresult) { - case LOOKUP_OK: - continue; - case LOOKUP_NOTFOUND: - sys.interface->wrln((char *)"word not found", 15); - stop = true; - break; - case LOOKUP_FAILED: - sys.interface->wrln((char *)"execution failed", 17); - stop = true; - break; - default: - sys.interface->wrln((char *)"*** the world is broken ***", 27); - exit(1); - } - - if (stop) { - stop = false; + if (!lookup(&token, &sys)) { break; } } + system_write_status(&sys); + sys.interface->newline(); switch (result) { case PARSE_OK: return false; case PARSE_EOB: - sys.interface->wrbuf(ok, 4); return true; case PARSE_LEN: sys.interface->wrln((char *)"parse error: token too long", 27); @@ -94,8 +60,10 @@ interpreter() static char linebuf[81]; while (true) { - write_dstack(); - sys.interface->wrch('\n'); + if (TRACE_STACK) { + write_dstack(sys.interface, sys.dstack); + sys.interface->newline(); + } sys.interface->wrch('?'); sys.interface->wrch(' '); buflen = sys.interface->rdbuf(linebuf, 80, true, '\n'); @@ -103,18 +71,19 @@ interpreter() } } -static char banner[] = "kforth interpreter\n"; -const size_t bannerlen = 19; +static char banner[] = "kforth interpreter"; +const size_t bannerlen = 18; int main(void) { + reset_system(&sys); init_dict(&sys); #ifdef __linux__ Console interface; sys.interface = &interface; #endif - sys.interface->wrbuf(banner, bannerlen); + sys.interface->wrln(banner, bannerlen); interpreter(); return 0; } \ No newline at end of file diff --git a/linux/defs.h b/linux/defs.h index 3740f5a..edcbdb2 100644 --- a/linux/defs.h +++ b/linux/defs.h @@ -5,6 +5,8 @@ #include typedef int32_t KF_INT; +typedef int64_t KF_LONG; + constexpr uint8_t STACK_SIZE = 128; #endif \ No newline at end of file diff --git a/linux/io.h b/linux/io.h index a64e7e4..7de9acb 100644 --- a/linux/io.h +++ b/linux/io.h @@ -17,6 +17,8 @@ public: // Line I/O bool rdln(char *buf, size_t len, size_t *readlen); void wrln(char *buf, size_t len); + + void newline(void) { this->wrch('\n'); }; private: }; diff --git a/parser.cc b/parser.cc index 5d26ba4..c52bd4d 100644 --- a/parser.cc +++ b/parser.cc @@ -5,7 +5,7 @@ #include #include -static void +static inline void reset(struct Token *t) { t->token = nullptr; @@ -48,9 +48,7 @@ parse_next(const char *buf, const size_t length, size_t *offset, { size_t cursor = *offset; - // Clear the token. reset(token); - if (cursor == length) { return PARSE_EOB; } diff --git a/stack.h b/stack.h index 849b710..a4f31a8 100644 --- a/stack.h +++ b/stack.h @@ -9,6 +9,7 @@ public: bool push(T val); bool pop(T *val); bool get(size_t, T &); + bool remove(size_t, T *); size_t size(void) { return this->arrlen; } void clear(void) { this->arrlen = 0; } private: @@ -56,4 +57,21 @@ Stack::get(size_t i, T &val) return true; } +// remove returns false on invalid bounds +template +bool +Stack::remove(size_t i, T *val) +{ + if (i > this->arrlen) { + return false; + } + + *val = this->arr[i]; + for (; i < (arrlen - 1); i++) { + this->arr[i] = this->arr[i+1]; + } + arrlen--; + return true; +} + #endif // __KF_STACK_H__ \ No newline at end of file diff --git a/system.cc b/system.cc new file mode 100644 index 0000000..aebd834 --- /dev/null +++ b/system.cc @@ -0,0 +1,64 @@ +#include "defs.h" +#include "system.h" + +#include + +constexpr static char STATE_STR_OK[] = "ok"; +constexpr static char STATE_STR_STACK_OVERFLOW[] = "stack overflow"; +constexpr static char STATE_STR_STACK_UNDERFLOW[] = "stack underflow"; +constexpr static char STATE_STR_EXECUTION_FAILURE[] = "execution failure"; +constexpr static char STATE_STR_UNKNOWN_WORD[] = "unknown word"; +constexpr static char STATE_STR_UNKNOWN_STATE[] = "undefined state"; +constexpr static char STATE_STR_ERROR_CODE[] = " (error code "; + +void +system_clear_error(System *sys) +{ + sys->status = STATUS_OK; +} + +void +system_write_status(System *sys) +{ + char *buf = nullptr; + size_t len = 0; + + if (sys->interface == nullptr) { + return; + } + + switch (sys->status) { + case STATUS_OK: + buf = (char *)(STATE_STR_OK); + len = sizeof STATE_STR_OK; + break; + case STATUS_STACK_OVERFLOW: + buf = (char *)(STATE_STR_STACK_OVERFLOW); + len = sizeof STATE_STR_STACK_OVERFLOW; + break; + case STATUS_STACK_UNDERFLOW: + buf = (char *)(STATE_STR_STACK_UNDERFLOW); + len = sizeof STATE_STR_STACK_UNDERFLOW; + break; + case STATUS_EXECUTION_FAILURE: + buf = (char *)(STATE_STR_EXECUTION_FAILURE); + len = sizeof STATE_STR_EXECUTION_FAILURE; + break; + case STATUS_UNKNOWN_WORD: + buf = (char *)(STATE_STR_UNKNOWN_WORD); + len = sizeof STATE_STR_UNKNOWN_WORD; + break; + default: + buf = (char *)(STATE_STR_UNKNOWN_STATE); + len = sizeof STATE_STR_UNKNOWN_STATE; + break; + } + + sys->interface->wrbuf(buf, len); + if (sys->status != STATUS_OK) { + sys->interface->wrbuf((char *)STATE_STR_ERROR_CODE, sizeof STATE_STR_ERROR_CODE); + write_num(sys->interface, (KF_INT)sys->status); + sys->interface->wrch(')'); + } + sys->interface->wrch('.'); +} \ No newline at end of file diff --git a/system.h b/system.h index 00f4a34..91aa1fa 100644 --- a/system.h +++ b/system.h @@ -5,11 +5,24 @@ #include "io.h" #include "stack.h" +typedef enum _SYS_STATUS : uint8_t { + STATUS_OK = 0, + STATUS_STACK_OVERFLOW = 1, + STATUS_STACK_UNDERFLOW = 2, + STATUS_EXECUTION_FAILURE = 3, + STATUS_UNKNOWN_WORD = 4 +} SYS_STATUS; + +class Word; + typedef struct _System { Stack dstack; IO *interface; - struct Word *dict; + Word *dict; + SYS_STATUS status; } System; +void system_clear_error(System *sys); +void system_write_status(System *sys); #endif // __KF_CORE_H__ \ No newline at end of file