]> code.bitgloo.com Git - clyne/sforth.git/commitdiff
finish exceptionless impl; fix sp@ and pick
authorClyne Sullivan <clyne@bitgloo.com>
Mon, 30 Dec 2024 20:08:49 +0000 (15:08 -0500)
committerClyne Sullivan <clyne@bitgloo.com>
Mon, 30 Dec 2024 20:08:49 +0000 (15:08 -0500)
main.cpp
sforth/forth.hpp

index e51f702a0901813c387a7190bb482001d5dc2d0a..697f2d2a6422fc4250ab15bc797334bf08af4ed9 100644 (file)
--- 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;
+                }
             }
         }
 
index 10b86bf0f98093f682fb4c1ccdef0317fd91d0cd..857e27f5805ee3271b7d992ba796259d90e16dfd 100644 (file)
@@ -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