catch stack errors

main
Clyne 10 months ago
parent 3038586ad4
commit 73e9023af0
Signed by: clyne
GPG Key ID: 3267C8EBF3F9AFC7

@ -29,13 +29,13 @@ void jump(FuncList ip)
// LITERAL's run-time semantics: push the given value onto the stack. // LITERAL's run-time semantics: push the given value onto the stack.
static auto literall = WordWrap<[] { static auto literall = WordWrap<[] {
*++SP = (Cell)*++IP; push((Cell)*++IP);
}>(); }>();
void compileliteral() void compileliteral()
{ {
comma((Cell)literall); comma((Cell)literall);
comma(*SP--); comma(pop());
} }
bool haskey() bool haskey()
@ -114,11 +114,11 @@ void word()
auto here = (char *)HERE; auto here = (char *)HERE;
++HERE; ++HERE;
readword(*SP); readword(*sp());
here[0] = strlen(here + 1); here[0] = strlen(here + 1);
HERE = (Cell)here; HERE = (Cell)here;
*SP = HERE; *sp() = HERE;
} }
void colon() void colon()
@ -132,7 +132,7 @@ void colon()
// Build the Word structure. // Build the Word structure.
comma(HERE + 4 * sizeof(Cell)); // exec ptr comma(HERE + 4 * sizeof(Cell)); // exec ptr
comma(name); // name 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 comma(0); // immediate
// The word's execution begins with a prologue that technically performs // 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). // about if it is running words or routines (i.e. pre-defined words).
comma((Cell)+[](FuncList *ip) { comma((Cell)+[](FuncList *ip) {
++ip; ++ip;
*++RP = (Cell)IP; rpush((Cell)IP);
jump((FuncList)*ip); jump((FuncList)*ip);
}); });
// The actual function list will begin one Cell beyond here. // The actual function list will begin one Cell beyond here.
comma(HERE + sizeof(Cell)); comma(HERE + sizeof(Cell));
DICT[DIdxCompXt] = *SP - 2 * sizeof(Cell); DICT[DIdxCompXt] = *sp() - 2 * sizeof(Cell);
// Enter compiling state. // Enter compiling state.
STATE = -1; STATE = -1;
@ -159,7 +159,7 @@ void semic()
comma((Cell)fexit); comma((Cell)fexit);
// Complete the new word's linkage to make it usable. // Complete the new word's linkage to make it usable.
auto link = (Cell *)*SP--; auto link = (Cell *)pop();
*link = LATEST; *link = LATEST;
LATEST = (Cell)(link - 2); LATEST = (Cell)(link - 2);
@ -177,7 +177,7 @@ void tick()
// Look up the name and push the result. // Look up the name and push the result.
int len = HERE - (Cell)name - 1; int len = HERE - (Cell)name - 1;
auto word = find(name, len); auto word = find(name, len);
*++SP = (Cell)word; push((Cell)word);
// Deallocate `name`. // Deallocate `name`.
HERE = (Cell)name; HERE = (Cell)name;

@ -31,8 +31,8 @@ extern void getinput();
*/ */
constexpr auto fexit = WordWrap<[] { constexpr auto fexit = WordWrap<[] {
extern FuncList IP; extern FuncList IP;
extern Cell *RP; extern Cell rpop();
IP = reinterpret_cast<FuncList>(*RP--); IP = reinterpret_cast<FuncList>(rpop());
}>(); }>();
void jump(FuncList ip); /** Jumps to the given instruction pointer. */ void jump(FuncList ip); /** Jumps to the given instruction pointer. */

@ -22,31 +22,38 @@
#include <cctype> #include <cctype>
#include <cstdlib> #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 (start != end) {
if (auto word = find(start, end - start); word) { if (auto word = find(start, end - start); word) {
if (!word->immediate() && STATE) { if (!word->immediate() && STATE) {
comma((Cell)word->list); comma((Cell)word->list);
} else { } else {
execute1(word); result = execute1(word);
} }
} else if (isdigit(*start)) { } else if (isdigit(*start)) {
*++SP = std::atoi(start); push(std::atoi(start));
if (STATE) if (STATE)
compileliteral(); compileliteral();
} }
} }
return result;
} }
void parseSource() [[nodiscard]]
static Error parseSource()
{ {
auto result = Error::none;
char *start = nullptr; char *start = nullptr;
char *end; char *end;
char *s; char *s;
while (haskey()) { while (result == Error::none && haskey()) {
s = (char *)DICT[DIdxSource]; s = (char *)DICT[DIdxSource];
++DICT[DIdxSource]; ++DICT[DIdxSource];
@ -54,7 +61,7 @@ void parseSource()
if (isspace(*s)) { if (isspace(*s)) {
if (start) { if (start) {
parseword(start, end + 1); result = parseword(start, end + 1);
start = nullptr; start = nullptr;
} }
} else { } else {
@ -69,16 +76,19 @@ void parseSource()
// Parse the final word if it is non-empty. // Parse the final word if it is non-empty.
if (start) 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(). // Reset source buffer and try to fill it with getinput().
DICT[DIdxSource] = (Cell)&DICT[DIdxBegin]; DICT[DIdxSource] = (Cell)&DICT[DIdxBegin];
DICT[DIdxSrcLen] = 0; DICT[DIdxSrcLen] = 0;
getinput(); getinput();
parseSource(); return parseSource();
} }

@ -19,5 +19,6 @@
* Resets the source buffer, calls getinput() to fill the source buffer, then * Resets the source buffer, calls getinput() to fill the source buffer, then
* parses the source buffer's contents. * parses the source buffer's contents.
*/ */
void parse(); [[nodiscard]]
Error parse();

@ -18,27 +18,63 @@
#include "core.hpp" #include "core.hpp"
#include "state.hpp" #include "state.hpp"
//#include <csetjmp> #include <csetjmp>
#include <cstring> #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; FuncList IP = nullptr;
std::array<Cell, DictSize> DICT; std::array<Cell, DictSize> DICT;
Cell& HERE = DICT[DIdxHere]; Cell& HERE = DICT[DIdxHere];
Cell& LATEST = DICT[DIdxLatest]; Cell& LATEST = DICT[DIdxLatest];
Cell& STATE = DICT[DIdxState]; Cell& STATE = DICT[DIdxState];
void executor(FuncList *list) static std::jmp_buf jmpbuf;
{ static Cell *SP = DICT.data() + DICT.size() - DS;
// TODO Use setjmp to recover from errors? static Cell *RP = DICT.data() + DICT.size() - DS - RS;
/*if (setjmp(jmpbuf) == 0)*/ {
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)
{
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. // We are given the pointer to a list of function pointers.
// Dereference once to retrieve the function pointer list. // Dereference once to retrieve the function pointer list.
@ -65,19 +101,19 @@ entry:
// their "calls". // their "calls".
// If the word is pre-defined then the argument will simply be // If the word is pre-defined then the argument will simply be
// ignored. // ignored.
entry = (void (*)(FuncList))*body; auto func = (void (*)(FuncList))*body;
entry(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 must initially be zero if executing a word at the top level.
IP = 0; IP = 0;
executor(&word->list); return executor(&word->list);
} }
Word *find(const char *s, int len) Word *find(const char *s, int len)

@ -42,11 +42,16 @@ extern std::array<Cell, DictSize> DICT;
extern Cell& HERE; /** Linked to HERE's storage in DICT. */ extern Cell& HERE; /** Linked to HERE's storage in DICT. */
extern Cell& LATEST; /** Linked to LATEST'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 Cell& STATE; /** Linked to STATE's storage in DICT. */
extern Cell *SP; /** Data stack pointer */
extern Cell *RP; /** Return stack pointer */
extern FuncList IP; /** Instruction 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. * Initializes the dictionary to default values.
* @param wordset The initial WordSet of pre-defined words. * @param wordset The initial WordSet of pre-defined words.
@ -63,13 +68,15 @@ inline void initialize(const auto& wordset)
* Begins execution with the given function pointer list. * Begins execution with the given function pointer list.
* @param list Function pointer list to execute * @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. * Executes the given word by calling executor on its definition.
* @param word The word to execute * @param word The word to execute
*/ */
void execute1(Word *word); [[nodiscard]]
Error execute1(Word *word);
/** /**
* Looks up the definition of the given word. * Looks up the definition of the given word.

@ -108,5 +108,13 @@ auto WordWrap = [] {
return list; return list;
}; };
enum class Error : int {
none = 1,
push,
pop,
rpush,
rpop
};
#endif // TYPES_HPP #endif // TYPES_HPP

@ -10,66 +10,65 @@
// TODO: // TODO:
// sys m* _/ _% _' depth _rdepth _in _ev find _uma u< um/mod // sys m* _/ _% _' depth _rdepth _in _ev find _uma u< um/mod
static void peek() { *SP = *(Cell *)(*SP); } static void peek() { *sp() = *(Cell *)(*sp()); }
static void commaSP() { comma(*SP--); } static void commaSP() { comma(pop()); }
static void push(Cell value) { *++SP = value; } static void discard() { auto v = pop(); (void)v; }
static void pop() { --SP; } static void tobool() { if (*sp()) *sp() = -1; }
static void tobool() { if (*SP) *SP = -1; }
constinit WordSet words ( constinit WordSet words (
Word("[", WordWrap<[] { STATE = 0; }>()).markImmediate(), Word("[", WordWrap<[] { STATE = 0; }>()).markImmediate(),
Word("]", WordWrap<[] { STATE = -1; }>()), Word("]", WordWrap<[] { STATE = -1; }>()),
Word("@", WordWrap<peek>()), Word("@", WordWrap<peek>()),
Word("c@", WordWrap<peek, [] { *SP &= 0xFF; }>()), Word("c@", WordWrap<peek, [] { *sp() &= 0xFF; }>()),
Word("!", WordWrap<[] { auto a = (Cell *)*SP--; *a = *SP--; }>()), Word("!", WordWrap<[] { auto a = (Cell *)pop(); *a = pop(); }>()),
Word("c!", WordWrap<[] { auto a = (char *)*SP--; *a = *SP--; }>()), Word("c!", WordWrap<[] { auto a = (char *)pop(); *a = pop(); }>()),
Word("_d", WordWrap<[] { *SP += (Cell)DICT.data(); }>()), Word("_d", WordWrap<[] { *sp() += (Cell)DICT.data(); }>()),
Word("_jmp", WordWrap<[] { jump((FuncList)*++IP); }>()), Word("_jmp", WordWrap<[] { jump((FuncList)*++IP); }>()),
Word("_jmp0", WordWrap<[] { Word("_jmp0", WordWrap<[] {
++IP; ++IP;
if (*SP-- == 0) if (pop() == 0)
jump((FuncList)*IP); jump((FuncList)*IP);
}>()), }>()),
Word(",", WordWrap<commaSP>()), 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(key()); }>()),
Word("key?", WordWrap<[] { push(haskey()); }, tobool>()), Word("key?", WordWrap<[] { push(haskey()); }, tobool>()),
Word("execute", WordWrap<[] { executor((FuncList *)*SP--); }>()), Word("execute", WordWrap<[] { (void)executor((FuncList *)pop()); }>()),
Word(":", WordWrap<colon>()), Word(":", WordWrap<colon>()),
Word(";", WordWrap<semic>()).markImmediate(), Word(";", WordWrap<semic>()).markImmediate(),
Word("exit", fexit), Word("exit", fexit),
Word("drop", WordWrap<pop>()), Word("drop", WordWrap<discard>()),
Word("dup", WordWrap<[] { push(*SP); }>()), Word("dup", WordWrap<[] { push(*sp()); }>()),
Word("swap", WordWrap<[] { std::swap(*SP, *(SP - 1)); }>()), Word("swap", WordWrap<[] { std::swap(*sp(), *(sp() - 1)); }>()),
Word("pick", WordWrap<[] { auto t = *(SP - *SP - 1); *SP = t; }>()), Word("pick", WordWrap<[] { auto t = *(sp() - *sp() - 1); *sp() = t; }>()),
Word("cells", WordWrap<[] { *SP *= sizeof(Cell); }>()), Word("cells", WordWrap<[] { *sp() *= sizeof(Cell); }>()),
Word("+", WordWrap<[] { *(SP - 1) += *SP; }, pop>()), Word("+", WordWrap<[] { *(sp() - 1) += *sp(); }, discard>()),
Word("-", WordWrap<[] { *(SP - 1) -= *SP; }, pop>()), Word("-", WordWrap<[] { *(sp() - 1) -= *sp(); }, discard>()),
Word("*", WordWrap<[] { *(SP - 1) *= *SP; }, pop>()), Word("*", WordWrap<[] { *(sp() - 1) *= *sp(); }, discard>()),
Word("/", WordWrap<[] { *(SP - 1) /= *SP; }, pop>()), Word("/", WordWrap<[] { *(sp() - 1) /= *sp(); }, discard>()),
Word("mod", WordWrap<[] { *(SP - 1) %= *SP; }, pop>()), Word("mod", WordWrap<[] { *(sp() - 1) %= *sp(); }, discard>()),
Word("=", WordWrap<[] { *(SP - 1) = *(SP - 1) == *SP; }, pop, tobool>()), Word("=", WordWrap<[] { *(sp() - 1) = *(sp() - 1) == *sp(); }, discard, tobool>()),
Word("<", WordWrap<[] { *(SP - 1) = *(SP - 1) < *SP; }, pop, tobool>()), Word("<", WordWrap<[] { *(sp() - 1) = *(sp() - 1) < *sp(); }, discard, tobool>()),
Word("or", WordWrap<[] { *(SP - 1) |= *SP; }, pop>()), Word("or", WordWrap<[] { *(sp() - 1) |= *sp(); }, discard>()),
Word("and", WordWrap<[] { *(SP - 1) &= *SP; }, pop>()), Word("and", WordWrap<[] { *(sp() - 1) &= *sp(); }, discard>()),
Word("xor", WordWrap<[] { *(SP - 1) ^= *SP; }, pop>()), Word("xor", WordWrap<[] { *(sp() - 1) ^= *sp(); }, discard>()),
Word("lshift", WordWrap<[] { *(SP - 1) <<= *SP; }, pop>()), Word("lshift", WordWrap<[] { *(sp() - 1) <<= *sp(); }, discard>()),
Word("rshift", WordWrap<[] { *(SP - 1) >>= *SP; }, pop>()), Word("rshift", WordWrap<[] { *(sp() - 1) >>= *sp(); }, discard>()),
Word(">r", WordWrap<[] { *++RP = *SP; }, pop>()), Word(">r", WordWrap<[] { rpush(pop()); }>()),
Word("r>", WordWrap<[] { push(*RP--); }>()), Word("r>", WordWrap<[] { push(rpop()); }>()),
Word("immediate", WordWrap<[] { ((Word *)LATEST)->markImmediate(); }>()), Word("immediate", WordWrap<[] { ((Word *)LATEST)->markImmediate(); }>()),
Word("aligned", WordWrap<[] { *SP = aligned(*SP); }>()), Word("aligned", WordWrap<[] { *sp() = aligned(*sp()); }>()),
Word("align", WordWrap<align>()), Word("align", WordWrap<align>()),
Word("literal", WordWrap<[] { if (STATE) compileliteral(); }>()).markImmediate(), Word("literal", WordWrap<[] { if (STATE) compileliteral(); }>()).markImmediate(),
Word("\'", WordWrap<tick>()), 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("[']", WordWrap<tick, compileliteral>()).markImmediate(),
Word("compile,", WordWrap<peek, commaSP>()), Word("compile,", WordWrap<peek, commaSP>()),
Word("word", WordWrap<word>()), Word("word", WordWrap<word>()),
Word("_b", WordWrap<[] { Word("_b", WordWrap<[] {
std::putchar('#'); // Gives a good breakpoint spot for gdb std::putchar('#'); // Gives a good breakpoint spot for gdb
}>()), }>()),
Word(".", WordWrap<[] { std::cout << *SP << ' '; }, pop>()) Word(".", WordWrap<[] { std::cout << pop() << ' '; }>())
); );
void getinput() void getinput()
@ -87,8 +86,12 @@ int main()
initialize(words); initialize(words);
while (std::cin.good()) { while (std::cin.good()) {
parse(); auto result = parse();
if (result == Error::none)
std::cout << (STATE ? "compiled" : "ok") << std::endl; std::cout << (STATE ? "compiled" : "ok") << std::endl;
else
std::cout << "error " << static_cast<int>(result) << std::endl;
} }
} }

Loading…
Cancel
Save