aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClyne Sullivan <clyne@bitgloo.com>2024-12-30 15:08:49 -0500
committerClyne Sullivan <clyne@bitgloo.com>2024-12-30 15:08:49 -0500
commit334a2a0727a71aa4c4cf953a4689cd22cf943ff6 (patch)
treeb6428197f4d7fd0fca37809b4ab26ffa687131c5
parentff4e488ca0fd012a4b632bf2f9a775a601c09f67 (diff)
finish exceptionless impl; fix sp@ and pick
-rw-r--r--main.cpp19
-rw-r--r--sforth/forth.hpp67
2 files changed, 66 insertions, 20 deletions
diff --git a/main.cpp b/main.cpp
index e51f702..697f2d2 100644
--- a/main.cpp
+++ b/main.cpp
@@ -23,7 +23,7 @@
#include <span>
#include <string>
-constinit static sforth::forth<4096> forth {sforth::initialize<&forth>()};
+constinit static sforth::forth<8192> forth {sforth::initialize<&forth>()};
static bool parse_stream(auto&, std::istream&, bool say_okay = false);
@@ -71,11 +71,18 @@ bool parse_stream(auto &fth, std::istream& str, bool say_okay)
if (sforth::isequal(line, "bye"))
return true;
- try {
- fth.parse_line(line);
- } catch (sforth::error e) {
- std::cerr << sforth::error_string(e) << " in " << line << std::endl;
- continue;
+ if constexpr (sforth::enable_exceptions) {
+ try {
+ fth.parse_line(line);
+ } catch (sforth::error e) {
+ std::cerr << sforth::error_string(e) << " in " << line << std::endl;
+ continue;
+ }
+ } else {
+ if (auto e = fth.parse_line(line); e) {
+ std::cerr << sforth::error_string(*e) << " in " << line << std::endl;
+ continue;
+ }
}
}
diff --git a/sforth/forth.hpp b/sforth/forth.hpp
index 10b86bf..857e27f 100644
--- a/sforth/forth.hpp
+++ b/sforth/forth.hpp
@@ -23,6 +23,7 @@
#include <algorithm>
#include <array>
#include <bit>
+#include <csetjmp>
#include <cstddef>
#include <string_view>
#include <utility>
@@ -31,9 +32,9 @@ namespace sforth {
constexpr bool enable_exceptions = true;
-enum class error
+enum class error : int
{
- init_error,
+ init_error = 1,
parse_error,
execute_error,
dictionary_overflow,
@@ -64,14 +65,36 @@ inline auto error_string(error err) noexcept -> std::string_view
}
#undef assert
-template<error Err>
-inline void assert(bool condition)
-{
- if constexpr (enable_exceptions) {
- if (!condition)
- throw Err;
+
+template<bool except>
+struct catcher {
+ constexpr catcher() = default;
+};
+
+template<> struct catcher<true> {
+ void operator()(error e) {
+ throw e;
+ }
+
+ std::optional<error> set() {
+ return {};
+ }
+};
+template<> struct catcher<false> {
+ std::jmp_buf buf = {};
+
+ void operator()(error e) {
+ std::longjmp(buf, static_cast<int>(e));
}
-}
+
+ std::optional<error> set() {
+ if (auto err = setjmp(buf); err) {
+ return static_cast<error>(err);
+ } else {
+ return {};
+ }
+ }
+};
template<std::size_t Cells>
struct forth : public word_list
@@ -81,6 +104,16 @@ struct forth : public word_list
static constexpr auto npos = std::string_view::npos;
+ template<error Err>
+ inline void assert(bool condition)
+ {
+ if (!condition) {
+ sp = dstack.end();
+ rp = rstack.end();
+ cat(Err);
+ }
+ }
+
void push(cell v) {
assert<error::stack_overflow>(sp != dstack.begin());
*--sp = v;
@@ -130,10 +163,13 @@ struct forth : public word_list
return word_list::parse(source, sourcei);
}
- void parse_line(std::string_view sv) {
+ std::optional<error> parse_line(std::string_view sv) {
source = sv.data();
sourcei = sv.find_first_not_of(" \t\r\n");
+ if (auto err = cat.set(); err)
+ return err;
+
while (sourcei != npos) {
const auto word = parse();
@@ -156,6 +192,8 @@ struct forth : public word_list
sourcei = sv.find_first_not_of(" \t\r\n", sourcei);
}
+
+ return {};
}
void execute(const func *body) {
@@ -179,6 +217,7 @@ struct forth : public word_list
std::size_t sourcei = npos;
cell compiling = false;
cell base = 10;
+ [[no_unique_address]] catcher<enable_exceptions> cat;
std::array<cell, data_size> dstack {};
std::array<func *, return_size> rstack {};
std::array<cell, Cells> dict {};
@@ -294,10 +333,10 @@ constexpr auto initialize()
fthp->ip = *std::bit_cast<func **>(ptr) - 1; }, 0
, S{"CHARS"}, [](auto) {}, 0
, S{"POSTPONE"}, [](auto) {
- assert<error::compile_only_word>(fthp->compiling);
+ fthp->template assert<error::compile_only_word>(fthp->compiling);
auto w = fthp->parse();
auto g = fthp->get(w);
- assert<error::word_not_found>(g.has_value());
+ fthp->template assert<error::word_not_found>(g.has_value());
if ((*g)->is_immediate()) {
*fthp->here++ = std::bit_cast<cell>((*g)->body());
@@ -353,8 +392,8 @@ constexpr auto initialize()
, S{">R" }, S{"RP@ CELL - RP ! RP@ CELL+ @ RP@ ! RP@ CELL+ !"}, 0
, S{"R>" }, S{"RP@ @ RP@ CELL+ RP ! RP@ @ SWAP RP@ !"}, 0
, S{"OVER" }, S{"1 PICK"}, 0
- , S{"PICK" }, S{"CELLS CELL+ SP@ + @"}, 0
- , S{"SP@" }, S{"SP @"}, 0
+ , S{"PICK" }, S{"1 + CELLS SP@ + @"}, 0
+ , S{"SP@" }, S{"SP @ CELL+"}, 0
, S{"RP@" }, S{"RP @ CELL+"}, 0
, S{"HERE" }, S{"DP @"}, 0
, S{"LATEST"}, S{"_D @"}, 0