diff --git a/core.fth b/core.fth index 9c6b7cf..a194aa1 100644 --- a/core.fth +++ b/core.fth @@ -1,5 +1,3 @@ -: unused [ _d 8 cells + ] literal @ here - ; - : ['] ' [ ' literal , ] ; immediate : if ['] _jmp0 , here 0 , ; immediate diff --git a/main.cpp b/main.cpp index 60653dc..0cc5640 100644 --- a/main.cpp +++ b/main.cpp @@ -22,37 +22,35 @@ #include #include -static std::array dict; -static sforth::forth *fth = - [] constexpr { - fth = new (dict.data()) sforth::forth; - sforth::initialize<&fth>(dict.end()); - return fth; - }(); +constinit static sforth::forth<1024> forth {sforth::initialize<&forth>()}; -static bool parse_stream(sforth::forth *, std::istream&, bool say_okay = false); +constinit static sforth::native_word<".", [](auto) { + char buf[32] = {}; + std::to_chars(buf, buf + sizeof(buf), forth.pop(), forth.base); + std::cout << buf << ' '; +}> dot; +constinit static sforth::native_word<"emit", [](auto) { + std::cout << static_cast(forth.pop()); +}, &dot> emit; + +static bool parse_stream(auto&, std::istream&, bool say_okay = false); int main(int argc, const char *argv[]) { std::span args (argv + 1, argc - 1); - fth->add(".", [](auto) { - char buf[32] = {}; - std::to_chars(buf, buf + sizeof(buf), fth->pop(), fth->base); - std::cout << buf << ' '; - }); - fth->add("emit", [](auto) { std::cout << static_cast(fth->pop()); }); - fth->add("dictsize", [](auto) { fth->push(dict.size() * sizeof(sforth::cell)); }); + + dot.next = std::exchange(forth.next, &emit); for (auto arg : args) { - if (std::ifstream file {arg}; parse_stream(fth, file)) + if (std::ifstream file {arg}; parse_stream(forth, file)) return 0; } - parse_stream(fth, std::cin, true); + parse_stream(forth, std::cin, true); } -bool parse_stream(sforth::forth *fth, std::istream& str, bool say_okay) +bool parse_stream(auto &fth, std::istream& str, bool say_okay) { std::string line; @@ -63,7 +61,7 @@ bool parse_stream(sforth::forth *fth, std::istream& str, bool say_okay) return true; try { - fth->parse_line(line); + fth.parse_line(line); } catch (sforth::error e) { std::cerr << sforth::error_string(e) << " in " << line << std::endl; continue; @@ -71,7 +69,7 @@ bool parse_stream(sforth::forth *fth, std::istream& str, bool say_okay) } if (say_okay) - std::cout << (fth->compiling ? "compiled" : "ok") << std::endl; + std::cout << (fth.compiling ? "compiled" : "ok") << std::endl; } return false; diff --git a/sforth/forth.hpp b/sforth/forth.hpp index 32f5d53..320a466 100644 --- a/sforth/forth.hpp +++ b/sforth/forth.hpp @@ -26,7 +26,6 @@ #include #include #include -#include #include namespace sforth { @@ -75,6 +74,7 @@ inline void assert(bool condition) } } +template struct forth : public word_list { static constexpr int data_size = 16; @@ -111,17 +111,6 @@ struct forth : public word_list return *rp++; } - template - auto pop() { - static_assert(N > 0, "pop() with N <= 0"); - - auto t = std::tuple {pop()}; - if constexpr (N > 1) - return std::tuple_cat(t, pop()); - else - return t; - } - forth& add(std::string_view name, func entry = nullptr) { const auto namesz = (name.size() + 1 + sizeof(cell) - 1) & ~(sizeof(cell) - 1); const auto size = (sizeof(word_base) + namesz) / sizeof(cell); @@ -176,109 +165,109 @@ struct forth : public word_list (*body)(body); } - constexpr forth() { + constexpr forth(const word_base *latest): + word_list{latest} + { sp = dstack.end(); rp = rstack.end(); + here = dict.begin(); } cell *sp; func **rp; func *ip = nullptr; - cell *here = std::bit_cast(this + 1); + cell *here; const char *source = nullptr; std::size_t sourcei = npos; cell compiling = false; - cell *end = nullptr; cell base = 10; - std::array dstack; - std::array rstack; + std::array dstack {}; + std::array rstack {}; + std::array dict {}; }; -template -void initialize(cell *end_value) +template +constexpr auto initialize() { - assert(*fthp); - - static auto& fth = **fthp; - static auto _d = std::bit_cast(*fthp); - constexpr static auto prologue = +[](const void *bodyf) { auto body = (func *)bodyf; - fth.rpush(fth.ip); + fthp->rpush(fthp->ip); - for (fth.ip = body + 1; *fth.ip; fth.ip++) - fth.execute(std::bit_cast(*fth.ip)); + for (fthp->ip = body + 1; *fthp->ip; fthp->ip++) + fthp->execute(std::bit_cast(*fthp->ip)); - fth.ip = fth.rpop(); + fthp->ip = fthp->rpop(); }; constexpr static func lit_impl = [](auto) { - auto ptr = std::bit_cast(++fth.ip); - fth.push(*ptr); + auto ptr = std::bit_cast(++fthp->ip); + fthp->push(*ptr); }; constexpr static auto& dict1 = native_dict< - S{"_d" }, [](auto) { fth.push(_d); }, 0 - , S{"sp" }, [](auto) { fth.push(_d + sizeof(cell)); }, 0 - , S{"rp" }, [](auto) { fth.push(_d + 2 * sizeof(cell)); }, 0 - , S{"ip" }, [](auto) { fth.push(_d + 3 * sizeof(cell)); }, 0 - , S{"dp" }, [](auto) { fth.push(_d + 4 * sizeof(cell)); }, 0 - , S{"state"}, [](auto) { fth.push(_d + 7 * sizeof(cell)); }, 0 - , S{"base" }, [](auto) { fth.push(_d + 9 * sizeof(cell)); }, 0 + S{"_d" }, [](auto) { fthp->push(std::bit_cast(fthp)); }, 0 + , S{"sp" }, [](auto) { fthp->push(std::bit_cast(fthp) + sizeof(cell)); }, 0 + , S{"rp" }, [](auto) { fthp->push(std::bit_cast(fthp) + 2 * sizeof(cell)); }, 0 + , S{"ip" }, [](auto) { fthp->push(std::bit_cast(fthp) + 3 * sizeof(cell)); }, 0 + , S{"dp" }, [](auto) { fthp->push(std::bit_cast(fthp) + 4 * sizeof(cell)); }, 0 + , S{"state"}, [](auto) { fthp->push(std::bit_cast(fthp) + 7 * sizeof(cell)); }, 0 + , S{"base" }, [](auto) { fthp->push(std::bit_cast(fthp) + 8 * sizeof(cell)); }, 0 + , S{"unused"}, [](auto) { fthp->push(sizeof(cell) * std::distance(fthp->here, fthp->dict.end())); }, 0 , S{"_lit" }, lit_impl, 0 - , S{"swap" }, [](auto) { auto [a, b] = fth.pop<2>(); fth.push(a, b); }, 0 - , S{"drop" }, [](auto) { fth.pop(); }, 0 - , S{"dup" }, [](auto) { fth.push(fth.top()); }, 0 - , S{"rot" }, [](auto) { auto [a, b, c] = fth.pop<3>(); fth.push(b, a, c); }, 0 - , S{"+" }, [](auto) { fth.top() += fth.pop(); }, 0 - , S{"-" }, [](auto) { fth.top() -= fth.pop(); }, 0 - , S{"*" }, [](auto) { fth.top() *= fth.pop(); }, 0 - , S{"/" }, [](auto) { fth.top() /= fth.pop(); }, 0 - , S{"mod" }, [](auto) { fth.top() %= fth.pop(); }, 0 - , S{"and" }, [](auto) { fth.top() &= fth.pop(); }, 0 - , S{"or" }, [](auto) { fth.top() |= fth.pop(); }, 0 - , S{"xor" }, [](auto) { fth.top() ^= fth.pop(); }, 0 - , S{"lshift"}, [](auto) { fth.top() <<= fth.pop(); }, 0 - , S{"rshift"}, [](auto) { fth.top() >>= fth.pop(); }, 0 - , S{"[" }, [](auto) { fth.compiling = false; }, word_base::immediate - , S{"]" }, [](auto) { fth.compiling = true; }, 0 - , S{"immediate"}, [](auto) { const_cast(fth.next)->make_immediate(); }, 0 + , S{"swap" }, [](auto) { auto a = fthp->pop(); auto b = fthp->pop(); fthp->push(a, b); }, 0 + , S{"drop" }, [](auto) { fthp->pop(); }, 0 + , S{"dup" }, [](auto) { fthp->push(fthp->top()); }, 0 + , S{"rot" }, [](auto) { auto a = fthp->pop(); auto b = fthp->pop(); auto c = fthp->pop(); + fthp->push(b, a, c); }, 0 + , S{"+" }, [](auto) { fthp->top() += fthp->pop(); }, 0 + , S{"-" }, [](auto) { fthp->top() -= fthp->pop(); }, 0 + , S{"*" }, [](auto) { fthp->top() *= fthp->pop(); }, 0 + , S{"/" }, [](auto) { fthp->top() /= fthp->pop(); }, 0 + , S{"mod" }, [](auto) { fthp->top() %= fthp->pop(); }, 0 + , S{"and" }, [](auto) { fthp->top() &= fthp->pop(); }, 0 + , S{"or" }, [](auto) { fthp->top() |= fthp->pop(); }, 0 + , S{"xor" }, [](auto) { fthp->top() ^= fthp->pop(); }, 0 + , S{"lshift"}, [](auto) { fthp->top() <<= fthp->pop(); }, 0 + , S{"rshift"}, [](auto) { fthp->top() >>= fthp->pop(); }, 0 + , S{"[" }, [](auto) { fthp->compiling = false; }, word_base::immediate + , S{"]" }, [](auto) { fthp->compiling = true; }, 0 + , S{"immediate"}, [](auto) { const_cast(fthp->next)->make_immediate(); }, 0 , S{"literal"}, [](auto) { - //assert(fth.compiling); - *fth.here++ = std::bit_cast(&lit_impl); - *fth.here++ = fth.pop(); }, word_base::immediate - , S{"@" }, [](auto) { fth.push(*std::bit_cast(fth.pop())); }, 0 - , S{"!" }, [](auto) { auto [p, v] = fth.pop<2>(); *std::bit_cast(p) = v; }, 0 - , S{"c@" }, [](auto) { fth.push(*std::bit_cast(fth.pop())); }, 0 - , S{"c!" }, [](auto) { auto [p, v] = fth.pop<2>(); *std::bit_cast(p) = v; }, 0 - , S{"=" }, [](auto) { auto v = fth.pop(); fth.top() = -(fth.top() == v); }, 0 - , S{"<" }, [](auto) { auto v = fth.pop(); fth.top() = -(fth.top() < v); }, 0 + //assert(fthp->compiling); + *fthp->here++ = std::bit_cast(&lit_impl); + *fthp->here++ = fthp->pop(); }, word_base::immediate + , S{"@" }, [](auto) { fthp->push(*std::bit_cast(fthp->pop())); }, 0 + , S{"!" }, [](auto) { auto p = fthp->pop(); *std::bit_cast(p) = fthp->pop(); }, 0 + , S{"c@" }, [](auto) { fthp->push(*std::bit_cast(fthp->pop())); }, 0 + , S{"c!" }, [](auto) { auto p = fthp->pop(); *std::bit_cast(p) = fthp->pop(); }, 0 + , S{"=" }, [](auto) { auto v = fthp->pop(); fthp->top() = -(fthp->top() == v); }, 0 + , S{"<" }, [](auto) { auto v = fthp->pop(); fthp->top() = -(fthp->top() < v); }, 0 , S{"\'" }, [](auto) { - auto w = fth.parse(); - auto g = fth.get(w); - fth.push(g ? std::bit_cast((*g)->body()) : 0); }, 0 + auto w = fthp->parse(); + auto g = fthp->get(w); + fthp->push(g ? std::bit_cast((*g)->body()) : 0); }, 0 , S{":" }, [](auto) { - auto w = fth.parse(); - fth.add(w); - *fth.here++ = std::bit_cast(prologue); - fth.compiling = true; }, 0 - , S{";" }, [](auto) { *fth.here++ = 0; fth.compiling = false; }, word_base::immediate - , S{"\\" }, [](auto) { fth.sourcei = forth::npos; }, word_base::immediate - , S{"cell" }, [](auto) { fth.push(sizeof(cell)); }, 0 + auto w = fthp->parse(); + fthp->add(w); + *fthp->here++ = std::bit_cast(prologue); + fthp->compiling = true; }, 0 + , S{";" }, [](auto) { *fthp->here++ = 0; fthp->compiling = false; }, word_base::immediate + , S{"\\" }, [](auto) { fthp->sourcei = std::string_view::npos; }, word_base::immediate + , S{"cell" }, [](auto) { fthp->push(sizeof(cell)); }, 0 , S{"_jmp" }, [](auto) { - auto ptr = ++fth.ip; - fth.ip = *std::bit_cast(ptr) - 1; }, 0 + auto ptr = ++fthp->ip; + fthp->ip = *std::bit_cast(ptr) - 1; }, 0 , S{"_jmp0"}, [](auto) { - auto ptr = ++fth.ip; - if (fth.pop() == 0) - fth.ip = *std::bit_cast(ptr) - 1; }, 0 + auto ptr = ++fthp->ip; + if (fthp->pop() == 0) + fthp->ip = *std::bit_cast(ptr) - 1; }, 0 , S{"chars"}, [](auto) {}, 0 , S{"postpone"}, [](auto) { - assert(fth.compiling); - auto w = fth.parse(); - auto g = fth.get(w); + assert(fthp->compiling); + auto w = fthp->parse(); + auto g = fthp->get(w); assert(g.has_value()); - *fth.here++ = std::bit_cast((*g)->body()); }, word_base::immediate + *fthp->here++ = std::bit_cast((*g)->body()); }, word_base::immediate >::word; constexpr static auto& dict2 = comp_dict::word; - fth.next = &dict2; - fth.end = end_value; + return &dict2; } } // namespace sforth @@ -334,8 +322,7 @@ void initialize(cell *end_value) //static_assert(offsetof(forth, source) == 5 * sizeof(cell)); //static_assert(offsetof(forth, sourcei) == 6 * sizeof(cell)); //static_assert(offsetof(forth, compiling) == 7 * sizeof(cell)); -//static_assert(offsetof(forth, end) == 8 * sizeof(cell)); -//static_assert(offsetof(forth, base) == 9 * sizeof(cell)); +//static_assert(offsetof(forth, base) == 8 * sizeof(cell)); #endif // SFORTH_HPP