|
|
@ -32,7 +32,7 @@ struct forth
|
|
|
|
{
|
|
|
|
{
|
|
|
|
using cell = std::intptr_t;
|
|
|
|
using cell = std::intptr_t;
|
|
|
|
using addr = std::uintptr_t;
|
|
|
|
using addr = std::uintptr_t;
|
|
|
|
using func = void (*)(void *);
|
|
|
|
using func = void (*)(const void *);
|
|
|
|
|
|
|
|
|
|
|
|
static constexpr bool enable_exceptions = true;
|
|
|
|
static constexpr bool enable_exceptions = true;
|
|
|
|
static constexpr int data_size = 16;
|
|
|
|
static constexpr int data_size = 16;
|
|
|
@ -64,19 +64,44 @@ struct forth
|
|
|
|
struct word_base {
|
|
|
|
struct word_base {
|
|
|
|
static constexpr addr immediate = 1 << 8;
|
|
|
|
static constexpr addr immediate = 1 << 8;
|
|
|
|
|
|
|
|
|
|
|
|
word_base *next;
|
|
|
|
const word_base *next;
|
|
|
|
addr flags_len;
|
|
|
|
addr flags_len;
|
|
|
|
|
|
|
|
|
|
|
|
auto name() const -> std::string_view {
|
|
|
|
auto name() const -> std::string_view {
|
|
|
|
return {reinterpret_cast<const char *>(this + 1)};
|
|
|
|
return {reinterpret_cast<const char *>(this + 1)};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
auto body() -> func * {
|
|
|
|
auto body() const -> const func * {
|
|
|
|
auto ptr = reinterpret_cast<std::uint8_t *>(this + 1) + (flags_len & 0xFF);
|
|
|
|
auto ptr = reinterpret_cast<const std::uint8_t *>(this + 1)
|
|
|
|
return reinterpret_cast<func *>(ptr);
|
|
|
|
+ (flags_len & 0xFF);
|
|
|
|
|
|
|
|
return reinterpret_cast<const func *>(ptr);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void make_immediate() {
|
|
|
|
|
|
|
|
flags_len |= immediate;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<std::size_t L>
|
|
|
|
|
|
|
|
struct word : public word_base {
|
|
|
|
|
|
|
|
std::array<char, L> name;
|
|
|
|
|
|
|
|
func body;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<std::size_t N>
|
|
|
|
|
|
|
|
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<std::size_t N>
|
|
|
|
|
|
|
|
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) {
|
|
|
|
void push(cell v) {
|
|
|
|
assert<error::stack_overflow>(sp != dstack.begin());
|
|
|
|
assert<error::stack_overflow>(sp != dstack.begin());
|
|
|
|
*--sp = v;
|
|
|
|
*--sp = v;
|
|
|
@ -138,11 +163,6 @@ struct forth
|
|
|
|
return *this;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
forth& make_immediate() {
|
|
|
|
|
|
|
|
latest->flags_len |= word_base::immediate;
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void parse_line(std::string_view sv) {
|
|
|
|
void parse_line(std::string_view sv) {
|
|
|
|
source = sv.data();
|
|
|
|
source = sv.data();
|
|
|
|
sourcei = sv.find_first_not_of(" \t\r\n");
|
|
|
|
sourcei = sv.find_first_not_of(" \t\r\n");
|
|
|
@ -183,12 +203,12 @@ struct forth
|
|
|
|
return word;
|
|
|
|
return word;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void execute(func *body) {
|
|
|
|
void execute(const func *body) {
|
|
|
|
assert<error::execute_error>(body && *body);
|
|
|
|
assert<error::execute_error>(body && *body);
|
|
|
|
(*body)(body);
|
|
|
|
(*body)(body);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
auto get(std::string_view sv) -> std::optional<word_base *> {
|
|
|
|
auto get(std::string_view sv) -> std::optional<const word_base *> {
|
|
|
|
for (auto lt = latest; lt; lt = lt->next) {
|
|
|
|
for (auto lt = latest; lt; lt = lt->next) {
|
|
|
|
if (sv == lt->name())
|
|
|
|
if (sv == lt->name())
|
|
|
|
return lt;
|
|
|
|
return lt;
|
|
|
@ -216,59 +236,81 @@ struct forth
|
|
|
|
|
|
|
|
|
|
|
|
static auto& fth = **fthp;
|
|
|
|
static auto& fth = **fthp;
|
|
|
|
|
|
|
|
|
|
|
|
fth.end = end_value;
|
|
|
|
auto f_dict = [](auto) { fth.push(reinterpret_cast<cell>(&fth)); };
|
|
|
|
fth
|
|
|
|
auto f_add = [](auto) { fth.top() += fth.pop(); };
|
|
|
|
.add("_d", [](auto) { fth.push(reinterpret_cast<cell>(&fth)); })
|
|
|
|
auto f_minus = [](auto) { fth.top() -= fth.pop(); };
|
|
|
|
//.add("[", [](auto) { fth.compiling = false; }).make_immediate()
|
|
|
|
auto f_times = [](auto) { fth.top() *= fth.pop(); };
|
|
|
|
//.add("]", [](auto) { fth.compiling = true; })
|
|
|
|
auto f_divide = [](auto) { fth.top() /= fth.pop(); };
|
|
|
|
.add("immediate", [](auto) { fth.make_immediate(); }).make_immediate()
|
|
|
|
auto f_bitand = [](auto) { fth.top() &= fth.pop(); };
|
|
|
|
.add("literal", [](auto) {
|
|
|
|
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<word_base *>(fth.latest)->make_immediate(); };
|
|
|
|
|
|
|
|
auto f_lit = [](auto) {
|
|
|
|
static auto lit_impl = +[] {
|
|
|
|
static auto lit_impl = +[] {
|
|
|
|
auto ptr = reinterpret_cast<cell *>(++fth.ip);
|
|
|
|
auto ptr = reinterpret_cast<cell *>(++fth.ip);
|
|
|
|
fth.push(*ptr);
|
|
|
|
fth.push(*ptr);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
assert<error::compile_only_word>(fth.compiling);
|
|
|
|
assert<error::compile_only_word>(fth.compiling);
|
|
|
|
*fth.here++ = reinterpret_cast<cell>(&lit_impl);
|
|
|
|
*fth.here++ = reinterpret_cast<cell>(&lit_impl);
|
|
|
|
*fth.here++ = fth.pop();
|
|
|
|
*fth.here++ = fth.pop(); };
|
|
|
|
}).make_immediate()
|
|
|
|
auto f_peek = [](auto) { fth.push(*reinterpret_cast<cell *>(fth.pop())); };
|
|
|
|
.add("@", [](auto) { fth.push(*reinterpret_cast<cell *>(fth.pop())); })
|
|
|
|
auto f_poke = [](auto) {
|
|
|
|
.add("!", [](auto) {
|
|
|
|
|
|
|
|
auto [p, v] = fth.pop<2>();
|
|
|
|
auto [p, v] = fth.pop<2>();
|
|
|
|
*reinterpret_cast<cell *>(p) = v; })
|
|
|
|
*reinterpret_cast<cell *>(p) = v; };
|
|
|
|
.add("swap", [](auto) { auto [a, b] = fth.pop<2>(); fth.push(a, b); })
|
|
|
|
auto f_swap = [](auto) { auto [a, b] = fth.pop<2>(); fth.push(a, b); };
|
|
|
|
//.add("drop", [](auto) { fth.pop(); })
|
|
|
|
auto f_drop = [](auto) { fth.pop(); };
|
|
|
|
//.add("dup", [](auto) { fth.push(fth.top()); })
|
|
|
|
auto f_dup = [](auto) { fth.push(fth.top()); };
|
|
|
|
//.add("rot", [](auto) { auto [a, b, c] = fth.pop<3>(); fth.push(b, a, c); })
|
|
|
|
auto f_rot = [](auto) { auto [a, b, c] = fth.pop<3>(); fth.push(b, a, c); };
|
|
|
|
.add("+", [](auto) { fth.top() += fth.pop(); })
|
|
|
|
auto f_eq = [](auto) { auto v = fth.pop(); fth.top() = -(fth.top() == v); };
|
|
|
|
.add("-", [](auto) { fth.top() -= fth.pop(); })
|
|
|
|
auto f_lt = [](auto) { auto v = fth.pop(); fth.top() = -(fth.top() < v); };
|
|
|
|
.add("*", [](auto) { fth.top() *= fth.pop(); })
|
|
|
|
auto f_tick = [](auto) {
|
|
|
|
.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();
|
|
|
|
auto w = fth.parse();
|
|
|
|
|
|
|
|
|
|
|
|
if (auto g = fth.get(w); g)
|
|
|
|
if (auto g = fth.get(w); g)
|
|
|
|
fth.push(reinterpret_cast<cell>((*g)->body()));
|
|
|
|
fth.push(reinterpret_cast<cell>((*g)->body()));
|
|
|
|
else
|
|
|
|
else
|
|
|
|
fth.push(0);
|
|
|
|
fth.push(0); };
|
|
|
|
})
|
|
|
|
auto f_colon = [](auto) {
|
|
|
|
.add(":", [](auto) {
|
|
|
|
|
|
|
|
auto w = fth.parse();
|
|
|
|
auto w = fth.parse();
|
|
|
|
fth.add(w);
|
|
|
|
fth.add(w);
|
|
|
|
*fth.here++ = reinterpret_cast<cell>(forth::prologue<fthp>);
|
|
|
|
*fth.here++ = reinterpret_cast<cell>(forth::prologue<fthp>);
|
|
|
|
fth.compiling = true;
|
|
|
|
fth.compiling = true; };
|
|
|
|
})
|
|
|
|
auto f_semic = [](auto) { *fth.here++ = 0; fth.compiling = false; };
|
|
|
|
.add(";", [](auto) {
|
|
|
|
auto f_comm = [](auto) { fth.sourcei = npos; };
|
|
|
|
*fth.here++ = 0;
|
|
|
|
auto f_cell = [](auto) { fth.push(sizeof(cell)); };
|
|
|
|
fth.compiling = false;
|
|
|
|
|
|
|
|
}).make_immediate()
|
|
|
|
constexpr static word w_dict {"_d", f_dict};
|
|
|
|
.add("\\", [](auto) {
|
|
|
|
constexpr static word w_add {"+", f_add, &w_dict};
|
|
|
|
fth.sourcei = npos;
|
|
|
|
constexpr static word w_minus {"-", f_minus, &w_add};
|
|
|
|
}).make_immediate();
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static auto error_string(error err) noexcept -> std::string_view {
|
|
|
|
static auto error_string(error err) noexcept -> std::string_view {
|
|
|
@ -297,7 +339,7 @@ struct forth
|
|
|
|
cell *rp;
|
|
|
|
cell *rp;
|
|
|
|
func *ip = nullptr;
|
|
|
|
func *ip = nullptr;
|
|
|
|
cell *here = reinterpret_cast<cell *>(this + 1);
|
|
|
|
cell *here = reinterpret_cast<cell *>(this + 1);
|
|
|
|
word_base *latest = nullptr;
|
|
|
|
const word_base *latest = nullptr;
|
|
|
|
const char *source = nullptr;
|
|
|
|
const char *source = nullptr;
|
|
|
|
std::size_t sourcei = npos;
|
|
|
|
std::size_t sourcei = npos;
|
|
|
|
cell compiling = false;
|
|
|
|
cell compiling = false;
|
|
|
|