From 334a2a0727a71aa4c4cf953a4689cd22cf943ff6 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Mon, 30 Dec 2024 15:08:49 -0500 Subject: [PATCH] finish exceptionless impl; fix sp@ and pick --- main.cpp | 19 +++++++++----- sforth/forth.hpp | 67 ++++++++++++++++++++++++++++++++++++++---------- 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 #include -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 #include #include +#include #include #include #include @@ -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 -inline void assert(bool condition) -{ - if constexpr (enable_exceptions) { - if (!condition) - throw Err; + +template +struct catcher { + constexpr catcher() = default; +}; + +template<> struct catcher { + void operator()(error e) { + throw e; + } + + std::optional set() { + return {}; + } +}; +template<> struct catcher { + std::jmp_buf buf = {}; + + void operator()(error e) { + std::longjmp(buf, static_cast(e)); } -} + + std::optional set() { + if (auto err = setjmp(buf); err) { + return static_cast(err); + } else { + return {}; + } + } +}; template struct forth : public word_list @@ -81,6 +104,16 @@ struct forth : public word_list static constexpr auto npos = std::string_view::npos; + template + inline void assert(bool condition) + { + if (!condition) { + sp = dstack.end(); + rp = rstack.end(); + cat(Err); + } + } + void push(cell v) { assert(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 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 cat; std::array dstack {}; std::array rstack {}; std::array dict {}; @@ -294,10 +333,10 @@ constexpr auto initialize() fthp->ip = *std::bit_cast(ptr) - 1; }, 0 , S{"CHARS"}, [](auto) {}, 0 , S{"POSTPONE"}, [](auto) { - assert(fthp->compiling); + fthp->template assert(fthp->compiling); auto w = fthp->parse(); auto g = fthp->get(w); - assert(g.has_value()); + fthp->template assert(g.has_value()); if ((*g)->is_immediate()) { *fthp->here++ = std::bit_cast((*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