|
|
@ -26,7 +26,6 @@
|
|
|
|
#include <cstddef>
|
|
|
|
#include <cstddef>
|
|
|
|
#include <charconv>
|
|
|
|
#include <charconv>
|
|
|
|
#include <string_view>
|
|
|
|
#include <string_view>
|
|
|
|
#include <tuple>
|
|
|
|
|
|
|
|
#include <utility>
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
|
|
|
|
namespace sforth {
|
|
|
|
namespace sforth {
|
|
|
@ -75,6 +74,7 @@ inline void assert(bool condition)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<std::size_t Cells>
|
|
|
|
struct forth : public word_list
|
|
|
|
struct forth : public word_list
|
|
|
|
{
|
|
|
|
{
|
|
|
|
static constexpr int data_size = 16;
|
|
|
|
static constexpr int data_size = 16;
|
|
|
@ -111,17 +111,6 @@ struct forth : public word_list
|
|
|
|
return *rp++;
|
|
|
|
return *rp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<int N>
|
|
|
|
|
|
|
|
auto pop() {
|
|
|
|
|
|
|
|
static_assert(N > 0, "pop<N>() with N <= 0");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto t = std::tuple {pop()};
|
|
|
|
|
|
|
|
if constexpr (N > 1)
|
|
|
|
|
|
|
|
return std::tuple_cat(t, pop<N - 1>());
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
return t;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
forth& add(std::string_view name, func entry = nullptr) {
|
|
|
|
forth& add(std::string_view name, func entry = nullptr) {
|
|
|
|
const auto namesz = (name.size() + 1 + sizeof(cell) - 1) & ~(sizeof(cell) - 1);
|
|
|
|
const auto namesz = (name.size() + 1 + sizeof(cell) - 1) & ~(sizeof(cell) - 1);
|
|
|
|
const auto size = (sizeof(word_base) + namesz) / sizeof(cell);
|
|
|
|
const auto size = (sizeof(word_base) + namesz) / sizeof(cell);
|
|
|
@ -176,109 +165,109 @@ struct forth : public word_list
|
|
|
|
(*body)(body);
|
|
|
|
(*body)(body);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
constexpr forth() {
|
|
|
|
constexpr forth(const word_base *latest):
|
|
|
|
|
|
|
|
word_list{latest}
|
|
|
|
|
|
|
|
{
|
|
|
|
sp = dstack.end();
|
|
|
|
sp = dstack.end();
|
|
|
|
rp = rstack.end();
|
|
|
|
rp = rstack.end();
|
|
|
|
|
|
|
|
here = dict.begin();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
cell *sp;
|
|
|
|
cell *sp;
|
|
|
|
func **rp;
|
|
|
|
func **rp;
|
|
|
|
func *ip = nullptr;
|
|
|
|
func *ip = nullptr;
|
|
|
|
cell *here = std::bit_cast<cell *>(this + 1);
|
|
|
|
cell *here;
|
|
|
|
const char *source = nullptr;
|
|
|
|
const char *source = nullptr;
|
|
|
|
std::size_t sourcei = npos;
|
|
|
|
std::size_t sourcei = npos;
|
|
|
|
cell compiling = false;
|
|
|
|
cell compiling = false;
|
|
|
|
cell *end = nullptr;
|
|
|
|
|
|
|
|
cell base = 10;
|
|
|
|
cell base = 10;
|
|
|
|
std::array<cell, data_size> dstack;
|
|
|
|
std::array<cell, data_size> dstack {};
|
|
|
|
std::array<func *, return_size> rstack;
|
|
|
|
std::array<func *, return_size> rstack {};
|
|
|
|
|
|
|
|
std::array<cell, Cells> dict {};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template<forth** fthp>
|
|
|
|
template<auto* fthp>
|
|
|
|
void initialize(cell *end_value)
|
|
|
|
constexpr auto initialize()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
assert<error::init_error>(*fthp);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static auto& fth = **fthp;
|
|
|
|
|
|
|
|
static auto _d = std::bit_cast<cell>(*fthp);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constexpr static auto prologue = +[](const void *bodyf) {
|
|
|
|
constexpr static auto prologue = +[](const void *bodyf) {
|
|
|
|
auto body = (func *)bodyf;
|
|
|
|
auto body = (func *)bodyf;
|
|
|
|
fth.rpush(fth.ip);
|
|
|
|
fthp->rpush(fthp->ip);
|
|
|
|
|
|
|
|
|
|
|
|
for (fth.ip = body + 1; *fth.ip; fth.ip++)
|
|
|
|
for (fthp->ip = body + 1; *fthp->ip; fthp->ip++)
|
|
|
|
fth.execute(std::bit_cast<func *>(*fth.ip));
|
|
|
|
fthp->execute(std::bit_cast<func *>(*fthp->ip));
|
|
|
|
|
|
|
|
|
|
|
|
fth.ip = fth.rpop();
|
|
|
|
fthp->ip = fthp->rpop();
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
constexpr static func lit_impl = [](auto) {
|
|
|
|
constexpr static func lit_impl = [](auto) {
|
|
|
|
auto ptr = std::bit_cast<cell *>(++fth.ip);
|
|
|
|
auto ptr = std::bit_cast<cell *>(++fthp->ip);
|
|
|
|
fth.push(*ptr);
|
|
|
|
fthp->push(*ptr);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
constexpr static auto& dict1 = native_dict<
|
|
|
|
constexpr static auto& dict1 = native_dict<
|
|
|
|
S{"_d" }, [](auto) { fth.push(_d); }, 0
|
|
|
|
S{"_d" }, [](auto) { fthp->push(std::bit_cast<cell>(fthp)); }, 0
|
|
|
|
, S{"sp" }, [](auto) { fth.push(_d + sizeof(cell)); }, 0
|
|
|
|
, S{"sp" }, [](auto) { fthp->push(std::bit_cast<cell>(fthp) + sizeof(cell)); }, 0
|
|
|
|
, S{"rp" }, [](auto) { fth.push(_d + 2 * sizeof(cell)); }, 0
|
|
|
|
, S{"rp" }, [](auto) { fthp->push(std::bit_cast<cell>(fthp) + 2 * sizeof(cell)); }, 0
|
|
|
|
, S{"ip" }, [](auto) { fth.push(_d + 3 * sizeof(cell)); }, 0
|
|
|
|
, S{"ip" }, [](auto) { fthp->push(std::bit_cast<cell>(fthp) + 3 * sizeof(cell)); }, 0
|
|
|
|
, S{"dp" }, [](auto) { fth.push(_d + 4 * sizeof(cell)); }, 0
|
|
|
|
, S{"dp" }, [](auto) { fthp->push(std::bit_cast<cell>(fthp) + 4 * sizeof(cell)); }, 0
|
|
|
|
, S{"state"}, [](auto) { fth.push(_d + 7 * sizeof(cell)); }, 0
|
|
|
|
, S{"state"}, [](auto) { fthp->push(std::bit_cast<cell>(fthp) + 7 * sizeof(cell)); }, 0
|
|
|
|
, S{"base" }, [](auto) { fth.push(_d + 9 * sizeof(cell)); }, 0
|
|
|
|
, S{"base" }, [](auto) { fthp->push(std::bit_cast<cell>(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{"_lit" }, lit_impl, 0
|
|
|
|
, S{"swap" }, [](auto) { auto [a, b] = fth.pop<2>(); fth.push(a, b); }, 0
|
|
|
|
, S{"swap" }, [](auto) { auto a = fthp->pop(); auto b = fthp->pop(); fthp->push(a, b); }, 0
|
|
|
|
, S{"drop" }, [](auto) { fth.pop(); }, 0
|
|
|
|
, S{"drop" }, [](auto) { fthp->pop(); }, 0
|
|
|
|
, S{"dup" }, [](auto) { fth.push(fth.top()); }, 0
|
|
|
|
, S{"dup" }, [](auto) { fthp->push(fthp->top()); }, 0
|
|
|
|
, S{"rot" }, [](auto) { auto [a, b, c] = fth.pop<3>(); fth.push(b, a, c); }, 0
|
|
|
|
, S{"rot" }, [](auto) { auto a = fthp->pop(); auto b = fthp->pop(); auto c = fthp->pop();
|
|
|
|
, S{"+" }, [](auto) { fth.top() += fth.pop(); }, 0
|
|
|
|
fthp->push(b, a, c); }, 0
|
|
|
|
, S{"-" }, [](auto) { fth.top() -= fth.pop(); }, 0
|
|
|
|
, S{"+" }, [](auto) { fthp->top() += fthp->pop(); }, 0
|
|
|
|
, S{"*" }, [](auto) { fth.top() *= fth.pop(); }, 0
|
|
|
|
, S{"-" }, [](auto) { fthp->top() -= fthp->pop(); }, 0
|
|
|
|
, S{"/" }, [](auto) { fth.top() /= fth.pop(); }, 0
|
|
|
|
, S{"*" }, [](auto) { fthp->top() *= fthp->pop(); }, 0
|
|
|
|
, S{"mod" }, [](auto) { fth.top() %= fth.pop(); }, 0
|
|
|
|
, S{"/" }, [](auto) { fthp->top() /= fthp->pop(); }, 0
|
|
|
|
, S{"and" }, [](auto) { fth.top() &= fth.pop(); }, 0
|
|
|
|
, S{"mod" }, [](auto) { fthp->top() %= fthp->pop(); }, 0
|
|
|
|
, S{"or" }, [](auto) { fth.top() |= fth.pop(); }, 0
|
|
|
|
, S{"and" }, [](auto) { fthp->top() &= fthp->pop(); }, 0
|
|
|
|
, S{"xor" }, [](auto) { fth.top() ^= fth.pop(); }, 0
|
|
|
|
, S{"or" }, [](auto) { fthp->top() |= fthp->pop(); }, 0
|
|
|
|
, S{"lshift"}, [](auto) { fth.top() <<= fth.pop(); }, 0
|
|
|
|
, S{"xor" }, [](auto) { fthp->top() ^= fthp->pop(); }, 0
|
|
|
|
, S{"rshift"}, [](auto) { fth.top() >>= fth.pop(); }, 0
|
|
|
|
, S{"lshift"}, [](auto) { fthp->top() <<= fthp->pop(); }, 0
|
|
|
|
, S{"[" }, [](auto) { fth.compiling = false; }, word_base::immediate
|
|
|
|
, S{"rshift"}, [](auto) { fthp->top() >>= fthp->pop(); }, 0
|
|
|
|
, S{"]" }, [](auto) { fth.compiling = true; }, 0
|
|
|
|
, S{"[" }, [](auto) { fthp->compiling = false; }, word_base::immediate
|
|
|
|
, S{"immediate"}, [](auto) { const_cast<word_base *>(fth.next)->make_immediate(); }, 0
|
|
|
|
, S{"]" }, [](auto) { fthp->compiling = true; }, 0
|
|
|
|
|
|
|
|
, S{"immediate"}, [](auto) { const_cast<word_base *>(fthp->next)->make_immediate(); }, 0
|
|
|
|
, S{"literal"}, [](auto) {
|
|
|
|
, S{"literal"}, [](auto) {
|
|
|
|
//assert<error::compile_only_word>(fth.compiling);
|
|
|
|
//assert<error::compile_only_word>(fthp->compiling);
|
|
|
|
*fth.here++ = std::bit_cast<cell>(&lit_impl);
|
|
|
|
*fthp->here++ = std::bit_cast<cell>(&lit_impl);
|
|
|
|
*fth.here++ = fth.pop(); }, word_base::immediate
|
|
|
|
*fthp->here++ = fthp->pop(); }, word_base::immediate
|
|
|
|
, S{"@" }, [](auto) { fth.push(*std::bit_cast<cell *>(fth.pop())); }, 0
|
|
|
|
, S{"@" }, [](auto) { fthp->push(*std::bit_cast<cell *>(fthp->pop())); }, 0
|
|
|
|
, S{"!" }, [](auto) { auto [p, v] = fth.pop<2>(); *std::bit_cast<cell *>(p) = v; }, 0
|
|
|
|
, S{"!" }, [](auto) { auto p = fthp->pop(); *std::bit_cast<cell *>(p) = fthp->pop(); }, 0
|
|
|
|
, S{"c@" }, [](auto) { fth.push(*std::bit_cast<char *>(fth.pop())); }, 0
|
|
|
|
, S{"c@" }, [](auto) { fthp->push(*std::bit_cast<char *>(fthp->pop())); }, 0
|
|
|
|
, S{"c!" }, [](auto) { auto [p, v] = fth.pop<2>(); *std::bit_cast<char *>(p) = v; }, 0
|
|
|
|
, S{"c!" }, [](auto) { auto p = fthp->pop(); *std::bit_cast<char *>(p) = fthp->pop(); }, 0
|
|
|
|
, S{"=" }, [](auto) { auto v = fth.pop(); fth.top() = -(fth.top() == v); }, 0
|
|
|
|
, S{"=" }, [](auto) { auto v = fthp->pop(); fthp->top() = -(fthp->top() == v); }, 0
|
|
|
|
, S{"<" }, [](auto) { auto v = fth.pop(); fth.top() = -(fth.top() < v); }, 0
|
|
|
|
, S{"<" }, [](auto) { auto v = fthp->pop(); fthp->top() = -(fthp->top() < v); }, 0
|
|
|
|
, S{"\'" }, [](auto) {
|
|
|
|
, S{"\'" }, [](auto) {
|
|
|
|
auto w = fth.parse();
|
|
|
|
auto w = fthp->parse();
|
|
|
|
auto g = fth.get(w);
|
|
|
|
auto g = fthp->get(w);
|
|
|
|
fth.push(g ? std::bit_cast<cell>((*g)->body()) : 0); }, 0
|
|
|
|
fthp->push(g ? std::bit_cast<cell>((*g)->body()) : 0); }, 0
|
|
|
|
, S{":" }, [](auto) {
|
|
|
|
, S{":" }, [](auto) {
|
|
|
|
auto w = fth.parse();
|
|
|
|
auto w = fthp->parse();
|
|
|
|
fth.add(w);
|
|
|
|
fthp->add(w);
|
|
|
|
*fth.here++ = std::bit_cast<cell>(prologue);
|
|
|
|
*fthp->here++ = std::bit_cast<cell>(prologue);
|
|
|
|
fth.compiling = true; }, 0
|
|
|
|
fthp->compiling = true; }, 0
|
|
|
|
, S{";" }, [](auto) { *fth.here++ = 0; fth.compiling = false; }, word_base::immediate
|
|
|
|
, S{";" }, [](auto) { *fthp->here++ = 0; fthp->compiling = false; }, word_base::immediate
|
|
|
|
, S{"\\" }, [](auto) { fth.sourcei = forth::npos; }, word_base::immediate
|
|
|
|
, S{"\\" }, [](auto) { fthp->sourcei = std::string_view::npos; }, word_base::immediate
|
|
|
|
, S{"cell" }, [](auto) { fth.push(sizeof(cell)); }, 0
|
|
|
|
, S{"cell" }, [](auto) { fthp->push(sizeof(cell)); }, 0
|
|
|
|
, S{"_jmp" }, [](auto) {
|
|
|
|
, S{"_jmp" }, [](auto) {
|
|
|
|
auto ptr = ++fth.ip;
|
|
|
|
auto ptr = ++fthp->ip;
|
|
|
|
fth.ip = *std::bit_cast<func **>(ptr) - 1; }, 0
|
|
|
|
fthp->ip = *std::bit_cast<func **>(ptr) - 1; }, 0
|
|
|
|
, S{"_jmp0"}, [](auto) {
|
|
|
|
, S{"_jmp0"}, [](auto) {
|
|
|
|
auto ptr = ++fth.ip;
|
|
|
|
auto ptr = ++fthp->ip;
|
|
|
|
if (fth.pop() == 0)
|
|
|
|
if (fthp->pop() == 0)
|
|
|
|
fth.ip = *std::bit_cast<func **>(ptr) - 1; }, 0
|
|
|
|
fthp->ip = *std::bit_cast<func **>(ptr) - 1; }, 0
|
|
|
|
, S{"chars"}, [](auto) {}, 0
|
|
|
|
, S{"chars"}, [](auto) {}, 0
|
|
|
|
, S{"postpone"}, [](auto) {
|
|
|
|
, S{"postpone"}, [](auto) {
|
|
|
|
assert<error::compile_only_word>(fth.compiling);
|
|
|
|
assert<error::compile_only_word>(fthp->compiling);
|
|
|
|
auto w = fth.parse();
|
|
|
|
auto w = fthp->parse();
|
|
|
|
auto g = fth.get(w);
|
|
|
|
auto g = fthp->get(w);
|
|
|
|
assert<error::word_not_found>(g.has_value());
|
|
|
|
assert<error::word_not_found>(g.has_value());
|
|
|
|
*fth.here++ = std::bit_cast<cell>((*g)->body()); }, word_base::immediate
|
|
|
|
*fthp->here++ = std::bit_cast<cell>((*g)->body()); }, word_base::immediate
|
|
|
|
>::word;
|
|
|
|
>::word;
|
|
|
|
constexpr static auto& dict2 = comp_dict<prologue, &dict1
|
|
|
|
constexpr static auto& dict2 = comp_dict<prologue, &dict1
|
|
|
|
, S{"align" }, S{"here dup aligned swap - allot"}, 0
|
|
|
|
, S{"align" }, S{"here dup aligned swap - allot"}, 0
|
|
|
@ -320,8 +309,7 @@ void initialize(cell *end_value)
|
|
|
|
, S{"bl" }, S{"32"}, 0
|
|
|
|
, S{"bl" }, S{"32"}, 0
|
|
|
|
>::word;
|
|
|
|
>::word;
|
|
|
|
|
|
|
|
|
|
|
|
fth.next = &dict2;
|
|
|
|
return &dict2;
|
|
|
|
fth.end = end_value;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace sforth
|
|
|
|
} // namespace sforth
|
|
|
@ -334,8 +322,7 @@ void initialize(cell *end_value)
|
|
|
|
//static_assert(offsetof(forth, source) == 5 * sizeof(cell));
|
|
|
|
//static_assert(offsetof(forth, source) == 5 * sizeof(cell));
|
|
|
|
//static_assert(offsetof(forth, sourcei) == 6 * sizeof(cell));
|
|
|
|
//static_assert(offsetof(forth, sourcei) == 6 * sizeof(cell));
|
|
|
|
//static_assert(offsetof(forth, compiling) == 7 * sizeof(cell));
|
|
|
|
//static_assert(offsetof(forth, compiling) == 7 * sizeof(cell));
|
|
|
|
//static_assert(offsetof(forth, end) == 8 * sizeof(cell));
|
|
|
|
//static_assert(offsetof(forth, base) == 8 * sizeof(cell));
|
|
|
|
//static_assert(offsetof(forth, base) == 9 * sizeof(cell));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif // SFORTH_HPP
|
|
|
|
#endif // SFORTH_HPP
|
|
|
|
|
|
|
|
|
|
|
|