|
|
@ -23,6 +23,7 @@
|
|
|
|
#include <algorithm>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <array>
|
|
|
|
#include <array>
|
|
|
|
#include <bit>
|
|
|
|
#include <bit>
|
|
|
|
|
|
|
|
#include <csetjmp>
|
|
|
|
#include <cstddef>
|
|
|
|
#include <cstddef>
|
|
|
|
#include <string_view>
|
|
|
|
#include <string_view>
|
|
|
|
#include <utility>
|
|
|
|
#include <utility>
|
|
|
@ -31,9 +32,9 @@ namespace sforth {
|
|
|
|
|
|
|
|
|
|
|
|
constexpr bool enable_exceptions = true;
|
|
|
|
constexpr bool enable_exceptions = true;
|
|
|
|
|
|
|
|
|
|
|
|
enum class error
|
|
|
|
enum class error : int
|
|
|
|
{
|
|
|
|
{
|
|
|
|
init_error,
|
|
|
|
init_error = 1,
|
|
|
|
parse_error,
|
|
|
|
parse_error,
|
|
|
|
execute_error,
|
|
|
|
execute_error,
|
|
|
|
dictionary_overflow,
|
|
|
|
dictionary_overflow,
|
|
|
@ -64,14 +65,36 @@ inline auto error_string(error err) noexcept -> std::string_view
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#undef assert
|
|
|
|
#undef assert
|
|
|
|
template<error Err>
|
|
|
|
|
|
|
|
inline void assert(bool condition)
|
|
|
|
template<bool except>
|
|
|
|
{
|
|
|
|
struct catcher {
|
|
|
|
if constexpr (enable_exceptions) {
|
|
|
|
constexpr catcher() = default;
|
|
|
|
if (!condition)
|
|
|
|
};
|
|
|
|
throw Err;
|
|
|
|
|
|
|
|
|
|
|
|
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>
|
|
|
|
template<std::size_t Cells>
|
|
|
|
struct forth : public word_list
|
|
|
|
struct forth : public word_list
|
|
|
@ -81,6 +104,16 @@ struct forth : public word_list
|
|
|
|
|
|
|
|
|
|
|
|
static constexpr auto npos = std::string_view::npos;
|
|
|
|
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) {
|
|
|
|
void push(cell v) {
|
|
|
|
assert<error::stack_overflow>(sp != dstack.begin());
|
|
|
|
assert<error::stack_overflow>(sp != dstack.begin());
|
|
|
|
*--sp = v;
|
|
|
|
*--sp = v;
|
|
|
@ -130,10 +163,13 @@ struct forth : public word_list
|
|
|
|
return word_list::parse(source, sourcei);
|
|
|
|
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();
|
|
|
|
source = sv.data();
|
|
|
|
sourcei = sv.find_first_not_of(" \t\r\n");
|
|
|
|
sourcei = sv.find_first_not_of(" \t\r\n");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (auto err = cat.set(); err)
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
|
|
|
|
while (sourcei != npos) {
|
|
|
|
while (sourcei != npos) {
|
|
|
|
const auto word = parse();
|
|
|
|
const auto word = parse();
|
|
|
|
|
|
|
|
|
|
|
@ -156,6 +192,8 @@ struct forth : public word_list
|
|
|
|
|
|
|
|
|
|
|
|
sourcei = sv.find_first_not_of(" \t\r\n", sourcei);
|
|
|
|
sourcei = sv.find_first_not_of(" \t\r\n", sourcei);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void execute(const func *body) {
|
|
|
|
void execute(const func *body) {
|
|
|
@ -179,6 +217,7 @@ struct forth : public word_list
|
|
|
|
std::size_t sourcei = npos;
|
|
|
|
std::size_t sourcei = npos;
|
|
|
|
cell compiling = false;
|
|
|
|
cell compiling = false;
|
|
|
|
cell base = 10;
|
|
|
|
cell base = 10;
|
|
|
|
|
|
|
|
[[no_unique_address]] catcher<enable_exceptions> cat;
|
|
|
|
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 {};
|
|
|
|
std::array<cell, Cells> dict {};
|
|
|
@ -294,10 +333,10 @@ constexpr auto initialize()
|
|
|
|
fthp->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>(fthp->compiling);
|
|
|
|
fthp->template assert<error::compile_only_word>(fthp->compiling);
|
|
|
|
auto w = fthp->parse();
|
|
|
|
auto w = fthp->parse();
|
|
|
|
auto g = fthp->get(w);
|
|
|
|
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()) {
|
|
|
|
if ((*g)->is_immediate()) {
|
|
|
|
*fthp->here++ = std::bit_cast<cell>((*g)->body());
|
|
|
|
*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@ CELL - RP ! RP@ CELL+ @ RP@ ! RP@ CELL+ !"}, 0
|
|
|
|
, S{"R>" }, S{"RP@ @ RP@ CELL+ RP ! RP@ @ SWAP RP@ !"}, 0
|
|
|
|
, S{"R>" }, S{"RP@ @ RP@ CELL+ RP ! RP@ @ SWAP RP@ !"}, 0
|
|
|
|
, S{"OVER" }, S{"1 PICK"}, 0
|
|
|
|
, S{"OVER" }, S{"1 PICK"}, 0
|
|
|
|
, S{"PICK" }, S{"CELLS CELL+ SP@ + @"}, 0
|
|
|
|
, S{"PICK" }, S{"1 + CELLS SP@ + @"}, 0
|
|
|
|
, S{"SP@" }, S{"SP @"}, 0
|
|
|
|
, S{"SP@" }, S{"SP @ CELL+"}, 0
|
|
|
|
, S{"RP@" }, S{"RP @ CELL+"}, 0
|
|
|
|
, S{"RP@" }, S{"RP @ CELL+"}, 0
|
|
|
|
, S{"HERE" }, S{"DP @"}, 0
|
|
|
|
, S{"HERE" }, S{"DP @"}, 0
|
|
|
|
, S{"LATEST"}, S{"_D @"}, 0
|
|
|
|
, S{"LATEST"}, S{"_D @"}, 0
|
|
|
|