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) { constinit static sforth::native_word<".", [](auto) {
char buf[32] = {}; char buf[32] = {};
std::to_chars(buf, buf + sizeof(buf), forth.pop(), forth.base); auto ptr = buf + sizeof(buf);
std::cout << buf << ' '; auto v = forth.pop();
*--ptr = '\0';
do {
*--ptr = "0123456789abcdefghijklmnopqrstuvwxyz"[v % forth.base];
} while (v /= forth.base);
std::cout << ptr << ' ';
}> dot; }> dot;
constinit static sforth::native_word<"emit", [](auto) { constinit static sforth::native_word<"emit", [](auto) {
std::cout << static_cast<char>(forth.pop()); 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); std::span args (argv + 1, argc - 1);
dot.next = std::exchange(forth.next, &emit); dot.next = std::exchange(forth.next, &emit);
for (auto arg : args) { for (auto arg : args) {

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

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

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

@ -31,6 +31,36 @@ using func = void (*)(const void *);
struct word_base; 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 struct word_list
{ {
const word_base *next; const word_base *next;
@ -45,7 +75,7 @@ struct word_list
const auto e = sv.find_first_of(" \t\r\n", sourcei); const auto e = sv.find_first_of(" \t\r\n", sourcei);
const auto word = e != std::string_view::npos ? const auto word = e != std::string_view::npos ?
sv.substr(sourcei, e - sourcei) : sv.substr(sourcei); sv.substr(sourcei, e - sourcei) : sv.substr(sourcei);
sourcei = sv.find_first_not_of(" \t\r\n", e); sourcei = sv.find_first_not_of(" \t\r\n", e);
return word; return word;
} }

Loading…
Cancel
Save