aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClyne Sullivan <clyne@bitgloo.com>2023-11-26 16:48:02 -0500
committerClyne Sullivan <clyne@bitgloo.com>2023-11-26 16:48:02 -0500
commit73e9023af0ea4ee56dc1d94190a14919f535eedc (patch)
tree7a6abdbf890fb92109a6210776961a4fe50f0e64
parent3038586ad459d58e3a621f155e5d2df69096bd39 (diff)
catch stack errors
-rw-r--r--source/core.cpp18
-rw-r--r--source/core.hpp4
-rw-r--r--source/parse.cpp28
-rw-r--r--source/parse.hpp3
-rw-r--r--source/state.cpp68
-rw-r--r--source/state.hpp17
-rw-r--r--source/types.hpp8
-rw-r--r--sprit.cpp75
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<FuncList>(*RP--);
+ extern Cell rpop();
+ IP = reinterpret_cast<FuncList>(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 <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();
}
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 <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)
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<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.
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<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;
}
}