From d8b279b7709410112002828199b0261508a9dda4 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Sat, 30 Nov 2024 13:03:08 -0500 Subject: [PATCH] roll our own from_chars --- main.cpp | 10 +++++++--- sforth/comp_word.hpp | 11 ++++++----- sforth/forth.hpp | 14 +++++--------- sforth/native_word.hpp | 2 +- sforth/types.hpp | 32 +++++++++++++++++++++++++++++++- 5 files changed, 50 insertions(+), 19 deletions(-) diff --git a/main.cpp b/main.cpp index 0cc5640..9453531 100644 --- a/main.cpp +++ b/main.cpp @@ -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(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) { diff --git a/sforth/comp_word.hpp b/sforth/comp_word.hpp index e75eee3..2b5978d 100644 --- a/sforth/comp_word.hpp +++ b/sforth/comp_word.hpp @@ -19,7 +19,7 @@ #include "native_word.hpp" -#include +#include namespace sforth { @@ -59,15 +59,16 @@ struct comp_word : public native_word 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(word, 10); + if (!n.has_value()) + std::unreachable(); bptr->f = Prev->get_ct("_lit"); bptr++; - bptr->c = n; + bptr->c = *n; bptr++; } } diff --git a/sforth/forth.hpp b/sforth/forth.hpp index 320a466..9e0a59e 100644 --- a/sforth/forth.hpp +++ b/sforth/forth.hpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -64,7 +63,7 @@ inline auto error_string(error err) noexcept -> std::string_view } } - +#undef assert template 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(e == std::errc() && p == word.cend()); + const auto n = from_chars(word, base); + assert(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 diff --git a/sforth/native_word.hpp b/sforth/native_word.hpp index da69b09..e3cb867 100644 --- a/sforth/native_word.hpp +++ b/sforth/native_word.hpp @@ -30,7 +30,7 @@ struct native_word : public word_base std::array 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) diff --git a/sforth/types.hpp b/sforth/types.hpp index d908b8f..3d26581 100644 --- a/sforth/types.hpp +++ b/sforth/types.hpp @@ -31,6 +31,36 @@ using func = void (*)(const void *); struct word_base; +template +constexpr std::optional 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; }