diff --git a/core.fth b/core.fth index 69ce9a2..3f850b1 100644 --- a/core.fth +++ b/core.fth @@ -1,12 +1,11 @@ -: cell 8 ; : cell+ cell + ; : cells cell * ; : char+ 1 + ; : chars ; -: state _d 7 cells + ; -: [ 0 state ! ; immediate -: ] -1 state ! ; +: state [ _d 7 cells + ] literal ; +\ : [ 0 state ! ; immediate +\ : ] -1 state ! ; : sp _d ; : rp [ _d cell+ ] literal ; @@ -19,8 +18,8 @@ : unused [ _d 8 cells + ] literal @ here - ; : latest [ _d 4 cells + ] literal @ ; -: dup sp@ @ ; -: drop sp@ cell+ sp ! ; +\ : dup sp@ @ ; +\ : drop sp@ cell+ sp ! ; : pick cells cell+ sp@ + @ ; : >r rp@ cell - rp ! rp@ cell+ @ rp@ ! @@ -28,7 +27,7 @@ : r> rp@ @ rp@ cell+ rp ! rp@ @ swap rp@ ! ; -: rot >r swap r> swap ; +\ : rot >r swap r> swap ; : -rot rot rot ; : over 1 pick ; diff --git a/forth.hpp b/forth.hpp index c19c24e..3873c68 100644 --- a/forth.hpp +++ b/forth.hpp @@ -32,7 +32,7 @@ struct forth { using cell = std::intptr_t; using addr = std::uintptr_t; - using func = void (*)(void *); + using func = void (*)(const void *); static constexpr bool enable_exceptions = true; static constexpr int data_size = 16; @@ -64,19 +64,44 @@ struct forth struct word_base { static constexpr addr immediate = 1 << 8; - word_base *next; + const word_base *next; addr flags_len; auto name() const -> std::string_view { return {reinterpret_cast(this + 1)}; } - auto body() -> func * { - auto ptr = reinterpret_cast(this + 1) + (flags_len & 0xFF); - return reinterpret_cast(ptr); + auto body() const -> const func * { + auto ptr = reinterpret_cast(this + 1) + + (flags_len & 0xFF); + return reinterpret_cast(ptr); + } + + void make_immediate() { + flags_len |= immediate; + } + }; + + template + struct word : public word_base { + std::array name; + func body; + + template + consteval word(const char (&nam)[N], + func bod = nullptr, + const word_base *prev = nullptr, + addr flags = 0): + word_base{prev, L | flags}, name{}, body{bod} + { + std::copy(nam, nam + N, name.begin()); } }; + template + word(const char (&nam)[N], func b = nullptr, const word_base *w = nullptr, + addr flags = 0) -> word<(N + sizeof(cell)) & ~(sizeof(cell) - 1)>; + void push(cell v) { assert(sp != dstack.begin()); *--sp = v; @@ -138,11 +163,6 @@ struct forth return *this; } - forth& make_immediate() { - latest->flags_len |= word_base::immediate; - return *this; - } - void parse_line(std::string_view sv) { source = sv.data(); sourcei = sv.find_first_not_of(" \t\r\n"); @@ -183,12 +203,12 @@ struct forth return word; } - void execute(func *body) { + void execute(const func *body) { assert(body && *body); (*body)(body); } - auto get(std::string_view sv) -> std::optional { + auto get(std::string_view sv) -> std::optional { for (auto lt = latest; lt; lt = lt->next) { if (sv == lt->name()) return lt; @@ -216,59 +236,81 @@ struct forth static auto& fth = **fthp; + auto f_dict = [](auto) { fth.push(reinterpret_cast(&fth)); }; + auto f_add = [](auto) { fth.top() += fth.pop(); }; + auto f_minus = [](auto) { fth.top() -= fth.pop(); }; + auto f_times = [](auto) { fth.top() *= fth.pop(); }; + auto f_divide = [](auto) { fth.top() /= fth.pop(); }; + auto f_bitand = [](auto) { fth.top() &= fth.pop(); }; + auto f_bitor = [](auto) { fth.top() |= fth.pop(); }; + auto f_bitxor = [](auto) { fth.top() ^= fth.pop(); }; + auto f_lbrac = [](auto) { fth.compiling = false; }; + auto f_rbrac = [](auto) { fth.compiling = true; }; + auto f_imm = [](auto) { + const_cast(fth.latest)->make_immediate(); }; + auto f_lit = [](auto) { + static auto lit_impl = +[] { + auto ptr = reinterpret_cast(++fth.ip); + fth.push(*ptr); + }; + + assert(fth.compiling); + *fth.here++ = reinterpret_cast(&lit_impl); + *fth.here++ = fth.pop(); }; + auto f_peek = [](auto) { fth.push(*reinterpret_cast(fth.pop())); }; + auto f_poke = [](auto) { + auto [p, v] = fth.pop<2>(); + *reinterpret_cast(p) = v; }; + auto f_swap = [](auto) { auto [a, b] = fth.pop<2>(); fth.push(a, b); }; + auto f_drop = [](auto) { fth.pop(); }; + auto f_dup = [](auto) { fth.push(fth.top()); }; + auto f_rot = [](auto) { auto [a, b, c] = fth.pop<3>(); fth.push(b, a, c); }; + auto f_eq = [](auto) { auto v = fth.pop(); fth.top() = -(fth.top() == v); }; + auto f_lt = [](auto) { auto v = fth.pop(); fth.top() = -(fth.top() < v); }; + auto f_tick = [](auto) { + auto w = fth.parse(); + + if (auto g = fth.get(w); g) + fth.push(reinterpret_cast((*g)->body())); + else + fth.push(0); }; + auto f_colon = [](auto) { + auto w = fth.parse(); + fth.add(w); + *fth.here++ = reinterpret_cast(forth::prologue); + fth.compiling = true; }; + auto f_semic = [](auto) { *fth.here++ = 0; fth.compiling = false; }; + auto f_comm = [](auto) { fth.sourcei = npos; }; + auto f_cell = [](auto) { fth.push(sizeof(cell)); }; + + constexpr static word w_dict {"_d", f_dict}; + constexpr static word w_add {"+", f_add, &w_dict}; + constexpr static word w_minus {"-", f_minus, &w_add}; + constexpr static word w_times {"*", f_times, &w_minus}; + constexpr static word w_divide {"/", f_divide, &w_times}; + constexpr static word w_bitand {"and", f_bitand, &w_divide}; + constexpr static word w_bitor {"or", f_bitor, &w_bitand}; + constexpr static word w_bitxor {"xor", f_bitxor, &w_bitor}; + constexpr static word w_lbrac {"[", f_lbrac, &w_bitxor, word_base::immediate}; + constexpr static word w_rbrac {"]", f_rbrac, &w_lbrac}; + constexpr static word w_imm {"immediate", f_imm, &w_rbrac}; + constexpr static word w_lit {"literal", f_lit, &w_imm, word_base::immediate}; + constexpr static word w_peek {"@", f_peek, &w_lit}; + constexpr static word w_poke {"!", f_poke, &w_peek}; + constexpr static word w_swap {"swap", f_swap, &w_poke}; + constexpr static word w_drop {"drop", f_drop, &w_swap}; + constexpr static word w_dup {"dup", f_dup, &w_drop}; + constexpr static word w_rot {"rot", f_rot, &w_dup}; + constexpr static word w_eq {"=", f_eq, &w_rot}; + constexpr static word w_lt {"<", f_lt, &w_eq}; + constexpr static word w_tick {"\'", f_tick, &w_lt}; + constexpr static word w_colon {":", f_colon, &w_tick}; + constexpr static word w_semic {";", f_semic, &w_colon, word_base::immediate}; + constexpr static word w_comm {"\\", f_comm, &w_semic, word_base::immediate}; + constexpr static word w_cell {"cell", f_cell, &w_comm}; + + fth.latest = &w_cell; fth.end = end_value; - fth - .add("_d", [](auto) { fth.push(reinterpret_cast(&fth)); }) - //.add("[", [](auto) { fth.compiling = false; }).make_immediate() - //.add("]", [](auto) { fth.compiling = true; }) - .add("immediate", [](auto) { fth.make_immediate(); }).make_immediate() - .add("literal", [](auto) { - static auto lit_impl = +[] { - auto ptr = reinterpret_cast(++fth.ip); - fth.push(*ptr); - }; - assert(fth.compiling); - *fth.here++ = reinterpret_cast(&lit_impl); - *fth.here++ = fth.pop(); - }).make_immediate() - .add("@", [](auto) { fth.push(*reinterpret_cast(fth.pop())); }) - .add("!", [](auto) { - auto [p, v] = fth.pop<2>(); - *reinterpret_cast(p) = v; }) - .add("swap", [](auto) { auto [a, b] = fth.pop<2>(); fth.push(a, b); }) - //.add("drop", [](auto) { fth.pop(); }) - //.add("dup", [](auto) { fth.push(fth.top()); }) - //.add("rot", [](auto) { auto [a, b, c] = fth.pop<3>(); fth.push(b, a, c); }) - .add("+", [](auto) { fth.top() += fth.pop(); }) - .add("-", [](auto) { fth.top() -= fth.pop(); }) - .add("*", [](auto) { fth.top() *= fth.pop(); }) - .add("/", [](auto) { fth.top() /= fth.pop(); }) - .add("and", [](auto) { fth.top() &= fth.pop(); }) - .add("or", [](auto) { fth.top() |= fth.pop(); }) - .add("xor", [](auto) { fth.top() ^= fth.pop(); }) - .add("=", [](auto) { auto v = fth.pop(); fth.top() = -(fth.top() == v); }) - .add("<", [](auto) { auto v = fth.pop(); fth.top() = -(fth.top() < v); }) - .add("\'", [](auto) { - auto w = fth.parse(); - - if (auto g = fth.get(w); g) - fth.push(reinterpret_cast((*g)->body())); - else - fth.push(0); - }) - .add(":", [](auto) { - auto w = fth.parse(); - fth.add(w); - *fth.here++ = reinterpret_cast(forth::prologue); - fth.compiling = true; - }) - .add(";", [](auto) { - *fth.here++ = 0; - fth.compiling = false; - }).make_immediate() - .add("\\", [](auto) { - fth.sourcei = npos; - }).make_immediate(); } static auto error_string(error err) noexcept -> std::string_view { @@ -297,7 +339,7 @@ struct forth cell *rp; func *ip = nullptr; cell *here = reinterpret_cast(this + 1); - word_base *latest = nullptr; + const word_base *latest = nullptr; const char *source = nullptr; std::size_t sourcei = npos; cell compiling = false;