roll our own from_chars

main
Clyne 3 weeks ago
parent 5b81d9c76d
commit d8b279b770
Signed by: clyne
GPG Key ID: 3267C8EBF3F9AFC7

@ -26,8 +26,13 @@ constinit static sforth::forth<1024> forth {sforth::initialize<&forth>()};
constinit static sforth::native_word<".", [](auto) {
char buf[32] = {};
std::to_chars(buf, buf + sizeof(buf), forth.pop(), forth.base);
std::cout << buf << ' ';
auto ptr = buf + sizeof(buf);
auto v = forth.pop();
*--ptr = '\0';
do {
*--ptr = "0123456789abcdefghijklmnopqrstuvwxyz"[v % forth.base];
} while (v /= forth.base);
std::cout << ptr << ' ';
}> dot;
constinit static sforth::native_word<"emit", [](auto) {
std::cout << static_cast<char>(forth.pop());
@ -39,7 +44,6 @@ int main(int argc, const char *argv[])
{
std::span args (argv + 1, argc - 1);
dot.next = std::exchange(forth.next, &emit);
for (auto arg : args) {

@ -19,7 +19,7 @@
#include "native_word.hpp"
#include <charconv>
#include <utility>
namespace sforth {
@ -59,15 +59,16 @@ struct comp_word : public native_word<Name, Prol, Prev>
auto w = Prev->get_ct(word);
if (w) {
bptr->f = Prev->get_ct(word);
bptr->f = w;
bptr++;
} else {
cell n;
std::from_chars(word.cbegin(), word.cend(), n, 10);
const auto n = from_chars<cell>(word, 10);
if (!n.has_value())
std::unreachable();
bptr->f = Prev->get_ct("_lit");
bptr++;
bptr->c = n;
bptr->c = *n;
bptr++;
}
}

@ -24,7 +24,6 @@
#include <array>
#include <bit>
#include <cstddef>
#include <charconv>
#include <string_view>
#include <utility>
@ -64,7 +63,7 @@ inline auto error_string(error err) noexcept -> std::string_view
}
}
#undef assert
template<error Err>
inline void assert(bool condition)
{
@ -139,13 +138,10 @@ struct forth : public word_list
const auto word = parse();
if (auto ent = get(word); !ent) {
cell n;
const auto [p, e] = std::from_chars(word.cbegin(), word.cend(),
n, base);
assert<error::word_not_found>(e == std::errc() && p == word.cend());
const auto n = from_chars<cell>(word, base);
assert<error::word_not_found>(n.has_value());
push(n);
push(*n);
if (compiling)
execute((*get("literal"))->body());
@ -299,9 +295,9 @@ constexpr auto initialize()
, S{"char+" }, S{"1 +" }, 0
, S{"-rot" }, S{"rot rot"}, 0
, S{"2drop" }, S{"drop drop"}, 0
, S{"0=" }, S{"0 ="}, 0
, S{"0<" }, S{"0 <"}, 0
, S{"<>" }, S{"= 0="}, 0
, S{"0=" }, S{"0 ="}, 0
, S{">" }, S{"swap <"}, 0
, S{"invert"}, S{"-1 xor"}, 0
, S{"negate"}, S{"-1 *"}, 0

@ -30,7 +30,7 @@ struct native_word : public word_base
std::array<char, N> namebuf;
func body;
consteval const func *get_ct(std::string_view name) const {
constexpr const func *get_ct(std::string_view name) const {
if (name == std::string_view{Name.data})
return &body;
else if constexpr (Prev != nullptr)

@ -31,6 +31,36 @@ using func = void (*)(const void *);
struct word_base;
template<typename T>
constexpr std::optional<T> from_chars(std::string_view sv, int base = 10)
{
T res {};
bool neg = false;
for (auto ch : sv) {
if (ch >= '0' && ch <= '9') {
if (ch - '0' < base) {
res *= base;
res += ch - '0';
} else return {};
} else if (ch >= 'A' && ch <= 'Z') {
if (base > 10 && ch - 'A' < base - 10) {
res *= base;
res += ch - 'A';
} else return {};
} else if (ch >= 'a' && ch <= 'z') {
if (base > 10 && ch - 'a' < base - 10) {
res *= base;
res += ch - 'a';
} else return {};
} else if (ch == '-' && res == 0) {
neg = true;
} else return {};
}
return neg ? -res : res;
}
struct word_list
{
const word_base *next;
@ -45,7 +75,7 @@ struct word_list
const auto e = sv.find_first_of(" \t\r\n", sourcei);
const auto word = e != std::string_view::npos ?
sv.substr(sourcei, e - sourcei) : sv.substr(sourcei);
sourcei = sv.find_first_not_of(" \t\r\n", e);
return word;
}

Loading…
Cancel
Save