From 73e9023af0ea4ee56dc1d94190a14919f535eedc Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Sun, 26 Nov 2023 16:48:02 -0500 Subject: [PATCH] catch stack errors --- source/core.cpp | 18 ++++++------ source/core.hpp | 4 +-- source/parse.cpp | 28 ++++++++++++------ source/parse.hpp | 3 +- source/state.cpp | 68 ++++++++++++++++++++++++++++++++----------- source/state.hpp | 17 +++++++---- source/types.hpp | 8 ++++++ sprit.cpp | 75 +++++++++++++++++++++++++----------------------- 8 files changed, 143 insertions(+), 78 deletions(-) diff --git a/source/core.cpp b/source/core.cpp index c5d7f28..cc7c267 100644 --- a/source/core.cpp +++ b/source/core.cpp @@ -29,13 +29,13 @@ void jump(FuncList ip) // LITERAL's run-time semantics: push the given value onto the stack. static auto literall = WordWrap<[] { - *++SP = (Cell)*++IP; + push((Cell)*++IP); }>(); void compileliteral() { comma((Cell)literall); - comma(*SP--); + comma(pop()); } bool haskey() @@ -114,11 +114,11 @@ void word() auto here = (char *)HERE; ++HERE; - readword(*SP); + readword(*sp()); here[0] = strlen(here + 1); HERE = (Cell)here; - *SP = HERE; + *sp() = HERE; } void colon() @@ -132,7 +132,7 @@ void colon() // Build the Word structure. comma(HERE + 4 * sizeof(Cell)); // exec ptr comma(name); // name ptr - *++SP = (Cell)comma(0); // link (to be set by semic()) + push((Cell)comma(0)); // link (to be set by semic()) comma(0); // immediate // The word's execution begins with a prologue that technically performs @@ -141,13 +141,13 @@ void colon() // about if it is running words or routines (i.e. pre-defined words). comma((Cell)+[](FuncList *ip) { ++ip; - *++RP = (Cell)IP; + rpush((Cell)IP); jump((FuncList)*ip); }); // The actual function list will begin one Cell beyond here. comma(HERE + sizeof(Cell)); - DICT[DIdxCompXt] = *SP - 2 * sizeof(Cell); + DICT[DIdxCompXt] = *sp() - 2 * sizeof(Cell); // Enter compiling state. STATE = -1; @@ -159,7 +159,7 @@ void semic() comma((Cell)fexit); // Complete the new word's linkage to make it usable. - auto link = (Cell *)*SP--; + auto link = (Cell *)pop(); *link = LATEST; LATEST = (Cell)(link - 2); @@ -177,7 +177,7 @@ void tick() // Look up the name and push the result. int len = HERE - (Cell)name - 1; auto word = find(name, len); - *++SP = (Cell)word; + push((Cell)word); // Deallocate `name`. HERE = (Cell)name; diff --git a/source/core.hpp b/source/core.hpp index f5149cf..4e4c1e6 100644 --- a/source/core.hpp +++ b/source/core.hpp @@ -31,8 +31,8 @@ extern void getinput(); */ constexpr auto fexit = WordWrap<[] { extern FuncList IP; - extern Cell *RP; - IP = reinterpret_cast(*RP--); + extern Cell rpop(); + IP = reinterpret_cast(rpop()); }>(); void jump(FuncList ip); /** Jumps to the given instruction pointer. */ diff --git a/source/parse.cpp b/source/parse.cpp index cebf702..6f68c84 100644 --- a/source/parse.cpp +++ b/source/parse.cpp @@ -22,31 +22,38 @@ #include #include -static void parseword(const char *start, const char *end) +[[nodiscard]] +static Error parseword(const char *start, const char *end) { + auto result = Error::none; + if (start != end) { if (auto word = find(start, end - start); word) { if (!word->immediate() && STATE) { comma((Cell)word->list); } else { - execute1(word); + result = execute1(word); } } else if (isdigit(*start)) { - *++SP = std::atoi(start); + push(std::atoi(start)); if (STATE) compileliteral(); } } + + return result; } -void parseSource() +[[nodiscard]] +static Error parseSource() { + auto result = Error::none; char *start = nullptr; char *end; char *s; - while (haskey()) { + while (result == Error::none && haskey()) { s = (char *)DICT[DIdxSource]; ++DICT[DIdxSource]; @@ -54,7 +61,7 @@ void parseSource() if (isspace(*s)) { if (start) { - parseword(start, end + 1); + result = parseword(start, end + 1); start = nullptr; } } else { @@ -69,16 +76,19 @@ void parseSource() // Parse the final word if it is non-empty. if (start) - parseword(start, s + 1); + result = parseword(start, s + 1); + + return result; } -void parse() +[[nodiscard]] +Error parse() { // Reset source buffer and try to fill it with getinput(). DICT[DIdxSource] = (Cell)&DICT[DIdxBegin]; DICT[DIdxSrcLen] = 0; getinput(); - parseSource(); + return parseSource(); } diff --git a/source/parse.hpp b/source/parse.hpp index a6816f3..757cdae 100644 --- a/source/parse.hpp +++ b/source/parse.hpp @@ -19,5 +19,6 @@ * Resets the source buffer, calls getinput() to fill the source buffer, then * parses the source buffer's contents. */ -void parse(); +[[nodiscard]] +Error parse(); diff --git a/source/state.cpp b/source/state.cpp index a2f424c..5daa772 100644 --- a/source/state.cpp +++ b/source/state.cpp @@ -18,27 +18,63 @@ #include "core.hpp" #include "state.hpp" -//#include +#include #include -//static std::jmp_buf jmpbuf; -Cell *SP = DICT.data() + DICT.size() - DS; -Cell *RP = DICT.data() + DICT.size() - DS - RS; FuncList IP = nullptr; - std::array DICT; Cell& HERE = DICT[DIdxHere]; Cell& LATEST = DICT[DIdxLatest]; Cell& STATE = DICT[DIdxState]; -void executor(FuncList *list) +static std::jmp_buf jmpbuf; +static Cell *SP = DICT.data() + DICT.size() - DS; +static Cell *RP = DICT.data() + DICT.size() - DS - RS; + +void push(Cell value) { + if (SP >= DICT.data() + DICT.size()) + std::longjmp(jmpbuf, static_cast(Error::push)); + + *++SP = value; +} + +Cell pop() { + if (SP - 1 < DICT.data() + DICT.size() - DS) + std::longjmp(jmpbuf, static_cast(Error::pop)); + + return *SP--; +} + +Cell *sp() { + return SP; +} + +void rpush(Cell value) { + if (RP >= DICT.data() + DICT.size() - DS) + std::longjmp(jmpbuf, static_cast(Error::rpush)); + + *++RP = value; +} + +Cell rpop() { + if (RP - 1 < DICT.data() + DICT.size() - DS - RS) + std::longjmp(jmpbuf, static_cast(Error::rpop)); + + return *RP--; +} + +Cell *rp() { + return RP; +} + +Error executor(FuncList *list) { - // TODO Use setjmp to recover from errors? - /*if (setjmp(jmpbuf) == 0)*/ { + auto result = static_cast(setjmp(jmpbuf)); + FuncList body; - FuncList body; - void (*entry)(FuncList); + if (static_cast(result) == 0) { + result = Error::none; // We are given the pointer to a list of function pointers. // Dereference once to retrieve the function pointer list. @@ -65,19 +101,19 @@ entry: // their "calls". // If the word is pre-defined then the argument will simply be // ignored. - entry = (void (*)(FuncList))*body; - entry(body); + auto func = (void (*)(FuncList))*body; + func(body); } - - //std::longjmp(jmpbuf, 1); } + + return result; } -void execute1(Word *word) +Error execute1(Word *word) { // IP must initially be zero if executing a word at the top level. IP = 0; - executor(&word->list); + return executor(&word->list); } Word *find(const char *s, int len) diff --git a/source/state.hpp b/source/state.hpp index 17d8e69..8bdc5dc 100644 --- a/source/state.hpp +++ b/source/state.hpp @@ -42,10 +42,15 @@ extern std::array DICT; extern Cell& HERE; /** Linked to HERE's storage in DICT. */ extern Cell& LATEST; /** Linked to LATEST's storage in DICT. */ extern Cell& STATE; /** Linked to STATE's storage in DICT. */ +extern FuncList IP; /** Instruction pointer */ -extern Cell *SP; /** Data stack pointer */ -extern Cell *RP; /** Return stack pointer */ -extern FuncList IP; /** Instruction pointer */ +void push(Cell); +[[nodiscard]] Cell pop(); +[[nodiscard]] Cell *sp(); + +void rpush(Cell); +[[nodiscard]] Cell rpop(); +[[nodiscard]] Cell *rp(); /** * Initializes the dictionary to default values. @@ -63,13 +68,15 @@ inline void initialize(const auto& wordset) * Begins execution with the given function pointer list. * @param list Function pointer list to execute */ -void executor(FuncList *list); +[[nodiscard]] +Error executor(FuncList *list); /** * Executes the given word by calling executor on its definition. * @param word The word to execute */ -void execute1(Word *word); +[[nodiscard]] +Error execute1(Word *word); /** * Looks up the definition of the given word. diff --git a/source/types.hpp b/source/types.hpp index 461d835..fd0b81e 100644 --- a/source/types.hpp +++ b/source/types.hpp @@ -108,5 +108,13 @@ auto WordWrap = [] { return list; }; +enum class Error : int { + none = 1, + push, + pop, + rpush, + rpop +}; + #endif // TYPES_HPP diff --git a/sprit.cpp b/sprit.cpp index cee9b6c..8d71a51 100644 --- a/sprit.cpp +++ b/sprit.cpp @@ -10,66 +10,65 @@ // TODO: // sys m* _/ _% _' depth _rdepth _in _ev find _uma u< um/mod -static void peek() { *SP = *(Cell *)(*SP); } -static void commaSP() { comma(*SP--); } -static void push(Cell value) { *++SP = value; } -static void pop() { --SP; } -static void tobool() { if (*SP) *SP = -1; } +static void peek() { *sp() = *(Cell *)(*sp()); } +static void commaSP() { comma(pop()); } +static void discard() { auto v = pop(); (void)v; } +static void tobool() { if (*sp()) *sp() = -1; } constinit WordSet words ( Word("[", WordWrap<[] { STATE = 0; }>()).markImmediate(), Word("]", WordWrap<[] { STATE = -1; }>()), Word("@", WordWrap()), - Word("c@", WordWrap()), - Word("!", WordWrap<[] { auto a = (Cell *)*SP--; *a = *SP--; }>()), - Word("c!", WordWrap<[] { auto a = (char *)*SP--; *a = *SP--; }>()), - Word("_d", WordWrap<[] { *SP += (Cell)DICT.data(); }>()), + Word("c@", WordWrap()), + Word("!", WordWrap<[] { auto a = (Cell *)pop(); *a = pop(); }>()), + Word("c!", WordWrap<[] { auto a = (char *)pop(); *a = pop(); }>()), + Word("_d", WordWrap<[] { *sp() += (Cell)DICT.data(); }>()), Word("_jmp", WordWrap<[] { jump((FuncList)*++IP); }>()), Word("_jmp0", WordWrap<[] { ++IP; - if (*SP-- == 0) + if (pop() == 0) jump((FuncList)*IP); }>()), Word(",", WordWrap()), - Word("emit", WordWrap<[] { std::putchar(*SP); }, pop>()), + Word("emit", WordWrap<[] { std::putchar(pop()); }>()), Word("key", WordWrap<[] { push(key()); }>()), Word("key?", WordWrap<[] { push(haskey()); }, tobool>()), - Word("execute", WordWrap<[] { executor((FuncList *)*SP--); }>()), + Word("execute", WordWrap<[] { (void)executor((FuncList *)pop()); }>()), Word(":", WordWrap()), Word(";", WordWrap()).markImmediate(), Word("exit", fexit), - Word("drop", WordWrap()), - Word("dup", WordWrap<[] { push(*SP); }>()), - Word("swap", WordWrap<[] { std::swap(*SP, *(SP - 1)); }>()), - Word("pick", WordWrap<[] { auto t = *(SP - *SP - 1); *SP = t; }>()), - Word("cells", WordWrap<[] { *SP *= sizeof(Cell); }>()), - Word("+", WordWrap<[] { *(SP - 1) += *SP; }, pop>()), - Word("-", WordWrap<[] { *(SP - 1) -= *SP; }, pop>()), - Word("*", WordWrap<[] { *(SP - 1) *= *SP; }, pop>()), - Word("/", WordWrap<[] { *(SP - 1) /= *SP; }, pop>()), - Word("mod", WordWrap<[] { *(SP - 1) %= *SP; }, pop>()), - Word("=", WordWrap<[] { *(SP - 1) = *(SP - 1) == *SP; }, pop, tobool>()), - Word("<", WordWrap<[] { *(SP - 1) = *(SP - 1) < *SP; }, pop, tobool>()), - Word("or", WordWrap<[] { *(SP - 1) |= *SP; }, pop>()), - Word("and", WordWrap<[] { *(SP - 1) &= *SP; }, pop>()), - Word("xor", WordWrap<[] { *(SP - 1) ^= *SP; }, pop>()), - Word("lshift", WordWrap<[] { *(SP - 1) <<= *SP; }, pop>()), - Word("rshift", WordWrap<[] { *(SP - 1) >>= *SP; }, pop>()), - Word(">r", WordWrap<[] { *++RP = *SP; }, pop>()), - Word("r>", WordWrap<[] { push(*RP--); }>()), + Word("drop", WordWrap()), + Word("dup", WordWrap<[] { push(*sp()); }>()), + Word("swap", WordWrap<[] { std::swap(*sp(), *(sp() - 1)); }>()), + Word("pick", WordWrap<[] { auto t = *(sp() - *sp() - 1); *sp() = t; }>()), + Word("cells", WordWrap<[] { *sp() *= sizeof(Cell); }>()), + Word("+", WordWrap<[] { *(sp() - 1) += *sp(); }, discard>()), + Word("-", WordWrap<[] { *(sp() - 1) -= *sp(); }, discard>()), + Word("*", WordWrap<[] { *(sp() - 1) *= *sp(); }, discard>()), + Word("/", WordWrap<[] { *(sp() - 1) /= *sp(); }, discard>()), + Word("mod", WordWrap<[] { *(sp() - 1) %= *sp(); }, discard>()), + Word("=", WordWrap<[] { *(sp() - 1) = *(sp() - 1) == *sp(); }, discard, tobool>()), + Word("<", WordWrap<[] { *(sp() - 1) = *(sp() - 1) < *sp(); }, discard, tobool>()), + Word("or", WordWrap<[] { *(sp() - 1) |= *sp(); }, discard>()), + Word("and", WordWrap<[] { *(sp() - 1) &= *sp(); }, discard>()), + Word("xor", WordWrap<[] { *(sp() - 1) ^= *sp(); }, discard>()), + Word("lshift", WordWrap<[] { *(sp() - 1) <<= *sp(); }, discard>()), + Word("rshift", WordWrap<[] { *(sp() - 1) >>= *sp(); }, discard>()), + Word(">r", WordWrap<[] { rpush(pop()); }>()), + Word("r>", WordWrap<[] { push(rpop()); }>()), Word("immediate", WordWrap<[] { ((Word *)LATEST)->markImmediate(); }>()), - Word("aligned", WordWrap<[] { *SP = aligned(*SP); }>()), + Word("aligned", WordWrap<[] { *sp() = aligned(*sp()); }>()), Word("align", WordWrap()), Word("literal", WordWrap<[] { if (STATE) compileliteral(); }>()).markImmediate(), Word("\'", WordWrap()), - Word("_i", WordWrap<[] { *SP = ((Word *)*SP)->immediate(); }, tobool>()), + Word("_i", WordWrap<[] { *sp() = ((Word *)*sp())->immediate(); }, tobool>()), Word("[']", WordWrap()).markImmediate(), Word("compile,", WordWrap()), Word("word", WordWrap()), Word("_b", WordWrap<[] { std::putchar('#'); // Gives a good breakpoint spot for gdb }>()), - Word(".", WordWrap<[] { std::cout << *SP << ' '; }, pop>()) + Word(".", WordWrap<[] { std::cout << pop() << ' '; }>()) ); void getinput() @@ -87,8 +86,12 @@ int main() initialize(words); while (std::cin.good()) { - parse(); - std::cout << (STATE ? "compiled" : "ok") << std::endl; + auto result = parse(); + + if (result == Error::none) + std::cout << (STATE ? "compiled" : "ok") << std::endl; + else + std::cout << "error " << static_cast(result) << std::endl; } }