]> code.bitgloo.com Git - clyne/sprit-forth.git/commitdiff
catch stack errors
authorClyne Sullivan <clyne@bitgloo.com>
Sun, 26 Nov 2023 21:48:02 +0000 (16:48 -0500)
committerClyne Sullivan <clyne@bitgloo.com>
Sun, 26 Nov 2023 21:48:02 +0000 (16:48 -0500)
source/core.cpp
source/core.hpp
source/parse.cpp
source/parse.hpp
source/state.cpp
source/state.hpp
source/types.hpp
sprit.cpp

index c5d7f2897b132651333fe3f6ad9badcbe2d5fc44..cc7c267e39efd4e7e4a421b25a2759441a1a79e8 100644 (file)
@@ -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;
index f5149cf7ec27a3e9582f25d9273caca246ba5c81..4e4c1e600d1cb65c54c549fda12a4a1b54f95d21 100644 (file)
@@ -31,8 +31,8 @@ extern void getinput();
  */
 constexpr auto fexit = WordWrap<[] {
     extern FuncList IP;
-    extern Cell *RP;
-    IP = reinterpret_cast<FuncList>(*RP--);
+    extern Cell rpop();
+    IP = reinterpret_cast<FuncList>(rpop());
 }>();
 
 void jump(FuncList ip); /** Jumps to the given instruction pointer. */
index cebf702de8b161ad8c6936d5770e5cd06b0ed5f6..6f68c84e5bba6451b4f77b745c8cc539031c5086 100644 (file)
 #include <cctype>
 #include <cstdlib>
 
-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();
 }
 
index a6816f3280859cb298ae6aa5bb685ceeb4450d7d..757cdae61aab1d237edae9314cbbb030952642da 100644 (file)
@@ -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();
 
index a2f424c62456f111674a60106664f7af3e5d2234..5daa772153fb8c56bbdeb2ddef91efba20e19043 100644 (file)
 #include "core.hpp"
 #include "state.hpp"
 
-//#include <csetjmp>
+#include <csetjmp>
 #include <cstring>
 
-//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<Cell, DictSize> 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<int>(Error::push));
+
+    *++SP = value;
+}
+
+Cell pop() {
+    if (SP - 1 < DICT.data() + DICT.size() - DS)
+        std::longjmp(jmpbuf, static_cast<int>(Error::pop));
+
+    return *SP--;
+}
+
+Cell *sp() {
+    return SP;
+}
+
+void rpush(Cell value) {
+    if (RP >= DICT.data() + DICT.size() - DS)
+        std::longjmp(jmpbuf, static_cast<int>(Error::rpush));
+
+    *++RP = value;
+}
+
+Cell rpop() {
+    if (RP - 1 < DICT.data() + DICT.size() - DS - RS)
+        std::longjmp(jmpbuf, static_cast<int>(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<Error>(setjmp(jmpbuf));
+    FuncList body;
 
-        FuncList body;
-        void (*entry)(FuncList);
+    if (static_cast<int>(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)
index 17d8e694ddcd293f4913df2f56d7a73b0d0dd376..8bdc5dc9bc552dbc8882e55eb409f8a1fab0b9b0 100644 (file)
@@ -42,10 +42,15 @@ extern std::array<Cell, DictSize> 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.
index 461d8357fed4c52303bc19d9910577509cf66b85..fd0b81ea1cf0e3bc3ef19c534062d17f560f4dbd 100644 (file)
@@ -108,5 +108,13 @@ auto WordWrap = [] {
     return list;
 };
 
+enum class Error : int {
+    none = 1,
+    push,
+    pop,
+    rpush,
+    rpop
+};
+
 #endif // TYPES_HPP
 
index cee9b6c3211d533b23e0e4c23695c5596e1b9791..8d71a51899de6759ad8d3614c00c309a4f6e61f9 100644 (file)
--- a/sprit.cpp
+++ b/sprit.cpp
 // 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<peek>()),
-    Word("c@",        WordWrap<peek, [] { *SP &= 0xFF; }>()),
-    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<peek, [] { *sp() &= 0xFF; }>()),
+    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<commaSP>()),
-    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<colon>()),
     Word(";",         WordWrap<semic>()).markImmediate(),
     Word("exit",      fexit),
-    Word("drop",      WordWrap<pop>()),
-    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<discard>()),
+    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<align>()),
     Word("literal",   WordWrap<[] { if (STATE) compileliteral(); }>()).markImmediate(),
     Word("\'",        WordWrap<tick>()),
-    Word("_i",        WordWrap<[] { *SP = ((Word *)*SP)->immediate(); }, tobool>()),
+    Word("_i",        WordWrap<[] { *sp() = ((Word *)*sp())->immediate(); }, tobool>()),
     Word("[']",       WordWrap<tick, compileliteral>()).markImmediate(),
     Word("compile,",  WordWrap<peek, commaSP>()),
     Word("word",      WordWrap<word>()),
     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<int>(result) << std::endl;
     }
 }