diff options
author | Clyne Sullivan <clyne@bitgloo.com> | 2024-12-30 15:08:49 -0500 |
---|---|---|
committer | Clyne Sullivan <clyne@bitgloo.com> | 2024-12-30 15:08:49 -0500 |
commit | 334a2a0727a71aa4c4cf953a4689cd22cf943ff6 (patch) | |
tree | b6428197f4d7fd0fca37809b4ab26ffa687131c5 | |
parent | ff4e488ca0fd012a4b632bf2f9a775a601c09f67 (diff) |
finish exceptionless impl; fix sp@ and pick
-rw-r--r-- | main.cpp | 19 | ||||
-rw-r--r-- | sforth/forth.hpp | 67 |
2 files changed, 66 insertions, 20 deletions
@@ -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 |