aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClyne Sullivan <clyne@bitgloo.com>2024-06-12 06:55:37 -0400
committerClyne Sullivan <clyne@bitgloo.com>2024-06-12 06:55:37 -0400
commita79eaf8e16b50c7798d9a285da251df6bce43b32 (patch)
treee892c4d91591b783cf1ccc5d1f26c77181bed083
parentb82f1c1f7e7680aabc64547ef45d4ca13962bc17 (diff)
refactor, encapsulateHEADmain
-rw-r--r--Makefile2
-rw-r--r--source/core.cpp88
-rw-r--r--source/core.hpp9
-rw-r--r--source/executor.cpp75
-rw-r--r--source/executor.hpp53
-rw-r--r--source/parse.cpp27
-rw-r--r--source/parse.hpp2
-rw-r--r--source/state.cpp107
-rw-r--r--source/state.hpp94
-rw-r--r--source/types.hpp49
-rw-r--r--sprit.cpp92
11 files changed, 317 insertions, 281 deletions
diff --git a/Makefile b/Makefile
index 5b7f486..6d733e8 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
SRC := $(wildcard source/*.cpp)
OBJ := $(subst .cpp,.o,$(SRC))
-CXXFLAGS += -std=c++20 -ggdb -g3 -O0 \
+CXXFLAGS += -std=c++20 -ggdb -g3 -Os \
-Wall -Wextra -pedantic \
-Isource
diff --git a/source/core.cpp b/source/core.cpp
index e2da109..437c700 100644
--- a/source/core.cpp
+++ b/source/core.cpp
@@ -1,5 +1,5 @@
// sprit-forth: A portable subroutine-threaded Forth.
-// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
+// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Library General Public License as published by
@@ -16,36 +16,35 @@
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
#include "core.hpp"
-#include "state.hpp"
#include <cctype>
#include <cstring>
+static State state;
+
void jump(FuncList ip)
{
// IP is incremented before its next execution.
- IP = ip - 1;
+ Exec.ip = ip - 1;
}
-// LITERAL's run-time semantics: push the given value onto the stack.
-static auto literall = WordWrap<[] {
- push((Cell)*++IP);
-}>;
-
void compileliteral()
{
- comma((Cell)literall);
- comma(pop());
+ // LITERAL's run-time semantics: push the given value onto the stack.
+ comma((Cell)WordWrap<[] {
+ Forth.push((Cell)*++Exec.ip);
+ }>);
+ comma(Forth.pop());
}
bool haskey()
{
- return *((char *)&DICT[DIdxInBuf]) < DICT[DIdxSrcLen];
+ return Forth.sourcei < Forth.sourceu;
}
void addkey(int k)
{
- auto addr = DICT[DIdxSource] + (DICT[DIdxSrcLen]++);
+ auto addr = Forth.source + Forth.sourceu++;
auto ptr = reinterpret_cast<char *>(addr);
*ptr = static_cast<char>(k);
}
@@ -56,16 +55,16 @@ int key()
while (!haskey())
getinput();
- auto ptr = reinterpret_cast<char *>(DICT[DIdxSource]);
- int idx = (*((char *)&DICT[DIdxInBuf]))++;
+ auto ptr = reinterpret_cast<char *>(Forth.source);
+ int idx = Forth.sourcei++;
return ptr[idx];
}
Cell *comma(Cell n)
{
- const auto ptr = reinterpret_cast<Cell *>(HERE);
+ const auto ptr = reinterpret_cast<Cell *>(Forth.here);
*ptr = n;
- HERE += sizeof(Cell);
+ Forth.here += sizeof(Cell);
return ptr;
}
@@ -76,7 +75,7 @@ Addr aligned(Addr addr)
void align()
{
- HERE = aligned(HERE);
+ Forth.here = aligned(Forth.here);
}
static void readword(int ch)
@@ -89,9 +88,9 @@ static void readword(int ch)
// Collect the word's text.
char *ptr;
do {
- ptr = reinterpret_cast<char *>(HERE);
+ ptr = reinterpret_cast<char *>(Forth.here);
*ptr = k;
- ++HERE;
+ ++Forth.here;
if (!haskey())
break;
@@ -100,36 +99,37 @@ static void readword(int ch)
} while (k != ch);
// Add a null terminator.
- ptr = reinterpret_cast<char *>(HERE);
+ ptr = reinterpret_cast<char *>(Forth.here);
*ptr = '\0';
- ++HERE;
+ ++Forth.here;
}
void word()
{
- auto here = (char *)HERE;
- ++HERE;
+ auto here = (char *)Forth.here;
+ ++Forth.here;
- readword(*sp());
+ readword(*Forth.sp);
here[0] = strlen(here + 1);
- HERE = (Cell)here;
- *sp() = HERE;
+ Forth.here = (Cell)here;
+ *Forth.sp = Forth.here;
}
void colon()
{
// Collect (and store) the word's name.
align();
- auto name = HERE;
+ auto name = Forth.here;
readword(' ');
align();
// Build the Word structure.
- comma(HERE + 4 * sizeof(Cell)); // exec ptr
- comma(name); // name ptr
- push((Cell)comma(0)); // link (to be set by semic())
- comma(0); // immediate
+ Forth.push(Forth.here);
+ comma(Forth.here + 4 * sizeof(Cell)); // exec ptr
+ comma(name); // name ptr
+ comma(0); // link
+ comma(0); // immediate
// The word's execution begins with a prologue that technically performs
// the "call" to this word.
@@ -137,16 +137,15 @@ void colon()
// about if it is running words or routines (i.e. pre-defined words).
comma((Cell)+[](FuncList *ip) {
++ip;
- rpush((Cell)IP);
+ Forth.rpush((Cell)Exec.ip);
jump((FuncList)*ip);
});
// The actual function list will begin one Cell beyond here.
- comma(HERE + sizeof(Cell));
-
- DICT[DIdxCompXt] = *sp() - 2 * sizeof(Cell);
+ comma(Forth.here + sizeof(Cell));
// Enter compiling state.
- STATE = -1;
+ Forth.compxt = *Forth.sp;
+ Forth.state = -1;
}
void semic()
@@ -155,27 +154,26 @@ void semic()
comma((Cell)fexit);
// Complete the new word's linkage to make it usable.
- auto link = (Cell *)pop();
- *link = LATEST;
- LATEST = (Cell)(link - 2);
+ auto word = reinterpret_cast<Word *>(Forth.pop());
+ Forth.add(*word);
// Exit compilation state.
- STATE = 0;
+ Forth.state = 0;
}
// TODO define in Forth? ": ' bl word find drop ;"
void tick()
{
// Get the name to look up.
- auto name = (char *)HERE;
+ auto name = Forth.here;
readword(' ');
// Look up the name and push the result.
- int len = HERE - (Cell)name - 1;
- auto word = find(name, len);
- push((Cell)word);
+ int len = Forth.here - name - 1;
+ auto word = Forth.find((char *)name, len);
+ Forth.push((Cell)word);
// Deallocate `name`.
- HERE = (Cell)name;
+ Forth.here = name;
}
diff --git a/source/core.hpp b/source/core.hpp
index 8b220e4..935fc0c 100644
--- a/source/core.hpp
+++ b/source/core.hpp
@@ -1,5 +1,5 @@
// sprit-forth: A portable subroutine-threaded Forth.
-// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
+// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Library General Public License as published by
@@ -18,7 +18,8 @@
#ifndef CORE_HPP
#define CORE_HPP
-#include "types.hpp"
+#include "executor.hpp"
+#include "state.hpp"
/**
* To be implemented by the user: Adds available input to the source buffer.
@@ -30,9 +31,7 @@ extern void getinput();
* "Function exit" word, analagous to a function's return statement.
*/
constexpr auto fexit = WordWrap<[] {
- extern FuncList IP;
- extern Cell rpop();
- IP = reinterpret_cast<FuncList>(rpop());
+ Exec.ip = reinterpret_cast<FuncList>(Forth.rpop());
}>;
void jump(FuncList ip); /** Jumps to the given instruction pointer. */
diff --git a/source/executor.cpp b/source/executor.cpp
new file mode 100644
index 0000000..d86abed
--- /dev/null
+++ b/source/executor.cpp
@@ -0,0 +1,75 @@
+// sprit-forth: A portable subroutine-threaded Forth.
+// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
+//
+// This library is free software; you can redistribute it and/or modify it
+// under the terms of the GNU Library General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or (at your
+// option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for
+// more details.
+//
+// You should have received a copy of the GNU Library General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#include "executor.hpp"
+
+Executor Exec;
+
+Error Executor::executor(FuncList *list) noexcept
+{
+ auto result = static_cast<Error>(setjmp(jmpbuf));
+ FuncList body;
+
+ if (static_cast<int>(result) == 0) {
+ result = Error::none;
+
+ // We are given the pointer to a list of function pointers.
+ // Dereference once to retrieve the function pointer list.
+ // We do not work with IP initially since it needs to be set to zero if
+ // this is a top-level call/execution.
+ body = *list;
+
+ // Enter the execution loop.
+ goto entry;
+
+ // Execution continues so long as IP is not zero.
+ // If this is a top-level execution of a pre-defined word, then IP will
+ // remain zero'd and the loop will immediately exit.
+ // If this is a defined word's execution, then its "call" will overwrite
+ // IP (and push the initial zero-IP to the return stack); execution will
+ // continue until we return to the zero-IP.
+ while (ip) {
+ // Retrieve next function pointer list.
+ body = (FuncList)*++ip;
+entry:
+ // Dereference `body` to get the first function in the list.
+ // This is casted to take a FuncList as an argument since defined
+ // words need to know their addresses so that they can perform
+ // their "calls".
+ // If the word is pre-defined then the argument will simply be
+ // ignored.
+ auto func = (void (*)(FuncList))*body;
+ func(body);
+ }
+ }
+
+ return result;
+}
+
+Error Executor::execute1(Word *word) noexcept
+{
+ // IP must initially be zero if executing a word at the top level.
+ ip = nullptr;
+ return executor(&word->list);
+}
+
+[[noreturn]]
+void Executor::terminate(Error error) noexcept
+{
+ std::longjmp(jmpbuf, static_cast<int>(error));
+}
+
diff --git a/source/executor.hpp b/source/executor.hpp
new file mode 100644
index 0000000..2029080
--- /dev/null
+++ b/source/executor.hpp
@@ -0,0 +1,53 @@
+// sprit-forth: A portable subroutine-threaded Forth.
+// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
+//
+// This library is free software; you can redistribute it and/or modify it
+// under the terms of the GNU Library General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or (at your
+// option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for
+// more details.
+//
+// You should have received a copy of the GNU Library General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef EXECUTOR_HPP
+#define EXECUTOR_HPP
+
+#include "types.hpp"
+
+#include <csetjmp>
+
+class Executor
+{
+ std::jmp_buf jmpbuf;
+
+public:
+ FuncList ip = nullptr;
+
+ /**
+ * Begins execution with the given function pointer list.
+ * @param list Function pointer list to execute
+ */
+ [[nodiscard]]
+ Error executor(FuncList *list) noexcept;
+
+ /**
+ * Executes the given word by calling executor on its definition.
+ * @param word The word to execute
+ */
+ [[nodiscard]]
+ Error execute1(Word *word) noexcept;
+
+ [[noreturn]]
+ void terminate(Error error) noexcept;
+};
+
+extern Executor Exec;
+
+#endif // EXECUTOR_HPP
+
diff --git a/source/parse.cpp b/source/parse.cpp
index 27c514d..6e1d2bf 100644
--- a/source/parse.cpp
+++ b/source/parse.cpp
@@ -1,5 +1,5 @@
// sprit-forth: A portable subroutine-threaded Forth.
-// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
+// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Library General Public License as published by
@@ -16,6 +16,7 @@
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
#include "core.hpp"
+#include "executor.hpp"
#include "state.hpp"
#include "types.hpp"
@@ -34,16 +35,16 @@ static Error parseword(const char *start, const char *end)
auto result = Error::none;
if (start != end) {
- if (auto word = find(start, end - start); word) {
- if (!word->immediate() && STATE) {
+ if (auto word = Forth.find(start, end - start); word) {
+ if (!word->immediate() && Forth.state) {
comma((Cell)word->list);
} else {
- result = execute1(word);
+ result = Exec.execute1(word);
}
} else if (isdigit(*start) || (*start == '-' && isdigit(*(start + 1)))) {
- push(std::atoi(start));
+ Forth.push(std::atoi(start));
- if (STATE)
+ if (Forth.state)
compileliteral();
} else if (findword(start, end - start)) {
return Error::noword;
@@ -57,11 +58,11 @@ static Error parseword(const char *start, const char *end)
static Error parseSource()
{
auto result = Error::none;
- char *start = (char *)DICT[DIdxSource];
+ char *start = (char *)Forth.source;
char *end = start;
- auto& i = *((char *)&DICT[DIdxInBuf]);
+ auto& i = *((char *)&Forth.sourcei);
- while (result == Error::none && i < DICT[DIdxSrcLen]) {
+ while (result == Error::none && i < Forth.sourceu) {
if (isspace(*end) || *end == '\0') {
if (end - start < 1) {
start = ++end;
@@ -69,7 +70,7 @@ static Error parseSource()
} else {
++i; // discard the space
result = parseword(start, end);
- start = (char *)DICT[DIdxSource] + i;
+ start = (char *)Forth.source + i;
end = start;
}
} else {
@@ -85,9 +86,9 @@ static Error parseSource()
Error parse()
{
// Reset source buffer and try to fill it with getinput().
- DICT[DIdxSource] = (Cell)&DICT[DIdxInBuf] + 1;
- DICT[DIdxSrcLen] = 0;
- *((char *)&DICT[DIdxInBuf]) = 0;
+ Forth.source = (Cell)&Forth.sourcei + 1;
+ Forth.sourceu = 0;
+ Forth.sourcei = 0;
getinput();
addkey('\0');
diff --git a/source/parse.hpp b/source/parse.hpp
index 757cdae..0f97944 100644
--- a/source/parse.hpp
+++ b/source/parse.hpp
@@ -1,5 +1,5 @@
// sprit-forth: A portable subroutine-threaded Forth.
-// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
+// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Library General Public License as published by
diff --git a/source/state.cpp b/source/state.cpp
index 03ad95d..63c633a 100644
--- a/source/state.cpp
+++ b/source/state.cpp
@@ -1,5 +1,5 @@
// sprit-forth: A portable subroutine-threaded Forth.
-// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
+// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Library General Public License as published by
@@ -18,108 +18,41 @@
#include "core.hpp"
#include "state.hpp"
-#include <csetjmp>
#include <cstring>
-FuncList IP = nullptr;
-std::array<Cell, DictSize> DICT;
+State Forth;
-Cell& BASE = DICT[DIdxBase];
-Cell& HERE = DICT[DIdxHere];
-Cell& LATEST = DICT[DIdxLatest];
-Cell& STATE = DICT[DIdxState];
+void State::push(Cell value) {
+ if (sp >= ds.end())
+ Exec.terminate(Error::push);
-static std::jmp_buf jmpbuf;
-static Cell *SP = DICT.data() + DICT.size() - DS;
-static Cell *RP = DICT.data() + DICT.size() - DS - RS;
-
-void push(Cell value) {
- if (SP >= DICT.data() + DICT.size())
- std::longjmp(jmpbuf, static_cast<int>(Error::push));
-
- *++SP = value;
+ *++sp = value;
}
-Cell pop() {
- if (SP - 1 < DICT.data() + DICT.size() - DS)
- std::longjmp(jmpbuf, static_cast<int>(Error::pop));
+Cell State::pop() {
+ if (sp - 1 < ds.begin())
+ Exec.terminate(Error::pop);
- return *SP--;
+ return *sp--;
}
-Cell *sp() {
- return SP;
-}
-
-void rpush(Cell value) {
- if (RP >= DICT.data() + DICT.size() - DS)
- std::longjmp(jmpbuf, static_cast<int>(Error::rpush));
-
- *++RP = value;
-}
-
-Cell rpop() {
- if (RP - 1 < DICT.data() + DICT.size() - DS - RS)
- std::longjmp(jmpbuf, static_cast<int>(Error::rpop));
-
- return *RP--;
-}
+void State::rpush(Cell value) {
+ if (rp >= rs.end())
+ Exec.terminate(Error::rpush);
-Cell *rp() {
- return RP;
+ *++rp = value;
}
-Error executor(FuncList *list)
-{
- auto result = static_cast<Error>(setjmp(jmpbuf));
- FuncList body;
-
- if (static_cast<int>(result) == 0) {
- result = Error::none;
-
- // We are given the pointer to a list of function pointers.
- // Dereference once to retrieve the function pointer list.
- // We do not work with IP initially since it needs to be set to zero if
- // this is a top-level call/execution.
- body = *list;
+Cell State::rpop() {
+ if (rp - 1 < rs.begin())
+ Exec.terminate(Error::rpop);
- // Enter the execution loop.
- goto entry;
-
- // Execution continues so long as IP is not zero.
- // If this is a top-level execution of a pre-defined word, then IP will
- // remain zero'd and the loop will immediately exit.
- // If this is a defined word's execution, then its "call" will overwrite
- // IP (and push the initial zero-IP to the return stack); execution will
- // continue until we return to the zero-IP.
- while (IP) {
- // Retrieve next function pointer list.
- body = (FuncList)*++IP;
-entry:
- // Dereference `body` to get the first function in the list.
- // This is casted to take a FuncList as an argument since defined
- // words need to know their addresses so that they can perform
- // their "calls".
- // If the word is pre-defined then the argument will simply be
- // ignored.
- auto func = (void (*)(FuncList))*body;
- func(body);
- }
- }
-
- return result;
-}
-
-Error execute1(Word *word)
-{
- // IP must initially be zero if executing a word at the top level.
- IP = 0;
- return executor(&word->list);
+ return *rp--;
}
-Word *find(const char *s, int len)
+Word *State::find(const char *s, int len)
{
- for (auto w = (Word *)LATEST; w; w = w->link) {
+ for (auto w = latest; w; w = w->link) {
if (len == (int)strlen(w->name) && strncmp(s, w->name, len) == 0)
return w;
}
diff --git a/source/state.hpp b/source/state.hpp
index b6e5bcf..5667875 100644
--- a/source/state.hpp
+++ b/source/state.hpp
@@ -1,5 +1,5 @@
// sprit-forth: A portable subroutine-threaded Forth.
-// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
+// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Library General Public License as published by
@@ -34,58 +34,60 @@ constexpr Addr DIdxSrcLen = 6;
constexpr Addr DIdxInBuf = 7;
constexpr Addr DIdxBegin = DIdxInBuf + 80 * sizeof(char);
-/**
- * Memory chunk used to store the dictoinary and stacks.
- */
-extern std::array<Cell, DictSize> DICT;
+class State
+{
+ /**
+ * Memory chunk used to store the dictoinary and stacks.
+ */
+ std::array<Cell, DictSize> dict;
+ std::array<Cell, DS> ds;
+ std::array<Cell, RS> rs;
-extern Cell& BASE;
-extern Cell& HERE; /** Linked to HERE's storage in DICT. */
-extern Cell& LATEST; /** Linked to LATEST's storage in DICT. */
-extern Cell& STATE; /** Linked to STATE's storage in DICT. */
-extern FuncList IP; /** Instruction pointer */
+public:
+ Cell *sp = ds.begin();
+ Cell *rp = rs.begin();
+ Cell& base = dict[DIdxBase];
+ Cell& here = dict[DIdxHere];
+ Word *& latest = *(Word **)&dict[DIdxLatest];
+ Cell& state = dict[DIdxState];
+ Cell& compxt = dict[DIdxCompXt];
+ Cell& source = dict[DIdxSource];
+ Cell& sourceu = dict[DIdxSrcLen];
+ unsigned char& sourcei = *(unsigned char *)&dict[DIdxInBuf];
-void push(Cell);
-[[nodiscard]] Cell pop();
-[[nodiscard]] Cell *sp();
+ State() {
+ dict[DIdxBase] = 10;
+ dict[DIdxHere] = (Cell)&dict[DIdxBegin];
+ dict[DIdxLatest] = 0;//(Cell)&wordset.back();
+ dict[DIdxState] = 0;
+ }
-void rpush(Cell);
-[[nodiscard]] Cell rpop();
-[[nodiscard]] Cell *rp();
+ void add(Word& word) noexcept {
+ word.link = latest;
+ latest = &word;
+ }
-/**
- * Initializes the dictionary to default values.
- * @param wordset The initial WordSet of pre-defined words.
- */
-inline void initialize(const auto& wordset)
-{
- DICT[DIdxBase] = 10;
- DICT[DIdxHere] = (Cell)&DICT[DIdxBegin];
- DICT[DIdxLatest] = (Cell)wordset.latest;
- DICT[DIdxState] = 0;
-}
+ auto dictdata() noexcept {
+ return dict.data();
+ }
+
+ void push(Cell);
+ [[nodiscard]] Cell pop();
-/**
- * Begins execution with the given function pointer list.
- * @param list Function pointer list to execute
- */
-[[nodiscard]]
-Error executor(FuncList *list);
+ void rpush(Cell);
+ [[nodiscard]] Cell rpop();
-/**
- * Executes the given word by calling executor on its definition.
- * @param word The word to execute
- */
-[[nodiscard]]
-Error execute1(Word *word);
+ /**
+ * Looks up the definition of the given word.
+ * @param s The name of the word to find
+ * @param len The character count of the word's name
+ * @return Pointer to the word's definition or nullptr if not found
+ */
+ [[nodiscard]]
+ Word *find(const char *s, int len);
+};
-/**
- * Looks up the definition of the given word.
- * @param s The name of the word to find
- * @param len The character count of the word's name
- * @return Pointer to the word's definition or nullptr if not found
- */
-Word *find(const char *s, int len);
+extern State Forth;
#endif // STATE_HPP
diff --git a/source/types.hpp b/source/types.hpp
index 0552135..aedc0d3 100644
--- a/source/types.hpp
+++ b/source/types.hpp
@@ -1,5 +1,5 @@
// sprit-forth: A portable subroutine-threaded Forth.
-// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
+// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Library General Public License as published by
@@ -21,6 +21,7 @@
#include <array>
#include <cstddef>
#include <cstdint>
+#include <memory>
using Cell = intptr_t; /** Type of a dictionary's cell. */
using Addr = uintptr_t; /** Type of a dictionary address. */
@@ -34,6 +35,16 @@ static_assert(sizeof(Cell) == sizeof(Addr));
static_assert(sizeof(Cell) == sizeof(Func));
/**
+ * Wraps the given functions so that a function pointer list can be created
+ * and used for a word's definition.
+ */
+template<auto... funcs>
+constexpr auto WordWrap = []() noexcept {
+ constexpr static auto wrapper = +[] { (funcs(), ...); };
+ return &wrapper;
+}();
+
+/**
* @struct Word
* @brief Structure of a word's definition.
* A word has a name, a body (list of functions), a link to the next word
@@ -69,42 +80,6 @@ static_assert(offsetof(Word, link) == 2 * sizeof(Cell));
static_assert(offsetof(Word, imm) == 3 * sizeof(Cell));
static_assert(sizeof(Word) == 4 * sizeof(Cell));
-/**
- * @struct WordSet
- * @brief Groups a set of pre-defined words and links them.
- */
-template<typename... Words>
-struct WordSet
-{
- std::array<Word, sizeof...(Words)> words;
- Word *latest;
-
- /**
- * Stores the given pre-defined words into the `words` array and links
- * their definitions together. The resulting `latest` value can be used
- * to set the global LATEST.
- */
- constexpr WordSet(Words... ws):
- words {ws...}
- {
- auto it = words.begin();
- while (++it != words.end())
- it->link = it - 1;
-
- latest = &*words.rbegin();
- }
-};
-
-/**
- * Wraps the given functions so that a function pointer list can be created
- * and used for a word's definition.
- */
-template<auto... funcs>
-constexpr auto WordWrap = []() noexcept {
- constexpr static auto wrapper = +[] { (funcs(), ...); };
- return &wrapper;
-}();
-
enum class Error : int {
none = 1,
push,
diff --git a/sprit.cpp b/sprit.cpp
index 7b36d2f..faab084 100644
--- a/sprit.cpp
+++ b/sprit.cpp
@@ -1,5 +1,5 @@
// sprit-forth: A portable subroutine-threaded Forth.
-// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
+// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Library General Public License as published by
@@ -27,66 +27,66 @@
// TODO:
// sys m* _/ _% _' depth _rdepth _in _ev find _uma u< um/mod
-static void peek() { *sp() = *(Cell *)(*sp()); }
-static void commaSP() { comma(pop()); }
-static void discard() { auto v = pop(); (void)v; }
-static void tobool() { if (*sp()) *sp() = -1; }
+static void peek() { *Forth.sp = *(Cell *)(*Forth.sp); }
+static void commaSP() { comma(Forth.pop()); }
+static void discard() { auto v = Forth.pop(); (void)v; }
+static void tobool() { if (*Forth.sp) *Forth.sp = -1; }
-constinit WordSet words (
- Word("[", WordWrap<[] { STATE = 0; }>).markImmediate(),
- Word("]", WordWrap<[] { STATE = -1; }>),
+constinit std::array words {
+ Word("[", WordWrap<[] { Forth.state = 0; }>).markImmediate(),
+ Word("]", WordWrap<[] { Forth.state = -1; }>),
Word("@", WordWrap<peek>),
- Word("c@", WordWrap<peek, [] { *sp() &= 0xFF; }>),
- Word("!", WordWrap<[] { auto a = (Cell *)pop(); *a = pop(); }>),
- Word("c!", WordWrap<[] { auto a = (char *)pop(); *a = pop(); }>),
- Word("_d", WordWrap<[] { *sp() += (Cell)DICT.data(); }>),
- Word("_jmp", WordWrap<[] { jump((FuncList)*++IP); }>),
+ Word("c@", WordWrap<peek, [] { *Forth.sp &= 0xFF; }>),
+ Word("!", WordWrap<[] { auto a = (Cell *)Forth.pop(); *a = Forth.pop(); }>),
+ Word("c!", WordWrap<[] { auto a = (char *)Forth.pop(); *a = Forth.pop(); }>),
+ Word("_d", WordWrap<[] { *Forth.sp += (Cell)Forth.dictdata(); }>),
+ Word("_jmp", WordWrap<[] { jump((FuncList)*++Exec.ip); }>),
Word("_jmp0", WordWrap<[] {
- ++IP;
- if (pop() == 0)
- jump((FuncList)*IP);
+ ++Exec.ip;
+ if (Forth.pop() == 0)
+ jump((FuncList)*Exec.ip);
}>),
Word(",", WordWrap<commaSP>),
- Word("emit", WordWrap<[] { std::putchar(pop()); }>),
- Word("key", WordWrap<[] { push(key()); }>),
- Word("key?", WordWrap<[] { push(haskey()); }, tobool>),
- Word("execute", WordWrap<[] { (void)executor((FuncList *)pop()); }>),
+ Word("emit", WordWrap<[] { std::putchar(Forth.pop()); }>),
+ Word("key", WordWrap<[] { Forth.push(key()); }>),
+ Word("key?", WordWrap<[] { Forth.push(haskey()); }, tobool>),
+ Word("execute", WordWrap<[] { (void)Exec.executor((FuncList *)Forth.pop()); }>),
Word(":", WordWrap<colon>),
Word(";", WordWrap<semic>).markImmediate(),
Word("exit", fexit),
Word("drop", WordWrap<discard>),
- Word("dup", WordWrap<[] { push(*sp()); }>),
- Word("swap", WordWrap<[] { std::swap(*sp(), *(sp() - 1)); }>),
- Word("pick", WordWrap<[] { auto t = *(sp() - *sp() - 1); *sp() = t; }>),
- Word("cells", WordWrap<[] { *sp() *= sizeof(Cell); }>),
- Word("+", WordWrap<[] { *(sp() - 1) += *sp(); }, discard>),
- Word("-", WordWrap<[] { *(sp() - 1) -= *sp(); }, discard>),
- Word("*", WordWrap<[] { *(sp() - 1) *= *sp(); }, discard>),
- Word("/", WordWrap<[] { *(sp() - 1) /= *sp(); }, discard>),
- Word("mod", WordWrap<[] { *(sp() - 1) %= *sp(); }, discard>),
- Word("=", WordWrap<[] { *(sp() - 1) = *(sp() - 1) == *sp(); }, discard, tobool>),
- Word("<", WordWrap<[] { *(sp() - 1) = *(sp() - 1) < *sp(); }, discard, tobool>),
- Word("or", WordWrap<[] { *(sp() - 1) |= *sp(); }, discard>),
- Word("and", WordWrap<[] { *(sp() - 1) &= *sp(); }, discard>),
- Word("xor", WordWrap<[] { *(sp() - 1) ^= *sp(); }, discard>),
- Word("lshift", WordWrap<[] { *(sp() - 1) <<= *sp(); }, discard>),
- Word("rshift", WordWrap<[] { *(sp() - 1) >>= *sp(); }, discard>),
- Word(">r", WordWrap<[] { rpush(pop()); }>),
- Word("r>", WordWrap<[] { push(rpop()); }>),
- Word("immediate", WordWrap<[] { ((Word *)LATEST)->markImmediate(); }>),
- Word("aligned", WordWrap<[] { *sp() = aligned(*sp()); }>),
+ Word("dup", WordWrap<[] { Forth.push(*Forth.sp); }>),
+ Word("swap", WordWrap<[] { std::swap(*Forth.sp, *(Forth.sp - 1)); }>),
+ Word("pick", WordWrap<[] { auto t = *(Forth.sp - *Forth.sp - 1); *Forth.sp = t; }>),
+ Word("cells", WordWrap<[] { *Forth.sp *= sizeof(Cell); }>),
+ Word("+", WordWrap<[] { *(Forth.sp - 1) += *Forth.sp; }, discard>),
+ Word("-", WordWrap<[] { *(Forth.sp - 1) -= *Forth.sp; }, discard>),
+ Word("*", WordWrap<[] { *(Forth.sp - 1) *= *Forth.sp; }, discard>),
+ Word("/", WordWrap<[] { *(Forth.sp - 1) /= *Forth.sp; }, discard>),
+ Word("mod", WordWrap<[] { *(Forth.sp - 1) %= *Forth.sp; }, discard>),
+ Word("=", WordWrap<[] { *(Forth.sp - 1) = *(Forth.sp - 1) == *Forth.sp; }, discard, tobool>),
+ Word("<", WordWrap<[] { *(Forth.sp - 1) = *(Forth.sp - 1) < *Forth.sp; }, discard, tobool>),
+ Word("or", WordWrap<[] { *(Forth.sp - 1) |= *Forth.sp; }, discard>),
+ Word("and", WordWrap<[] { *(Forth.sp - 1) &= *Forth.sp; }, discard>),
+ Word("xor", WordWrap<[] { *(Forth.sp - 1) ^= *Forth.sp; }, discard>),
+ Word("lshift", WordWrap<[] { *(Forth.sp - 1) <<= *Forth.sp; }, discard>),
+ Word("rshift", WordWrap<[] { *(Forth.sp - 1) >>= *Forth.sp; }, discard>),
+ Word(">r", WordWrap<[] { Forth.rpush(Forth.pop()); }>),
+ Word("r>", WordWrap<[] { Forth.push(Forth.rpop()); }>),
+ Word("immediate", WordWrap<[] { Forth.latest->markImmediate(); }>),
+ Word("aligned", WordWrap<[] { *Forth.sp = aligned(*Forth.sp); }>),
Word("align", WordWrap<align>),
- Word("literal", WordWrap<[] { if (STATE) compileliteral(); }>).markImmediate(),
+ Word("literal", WordWrap<[] { if (Forth.state) compileliteral(); }>).markImmediate(),
Word("\'", WordWrap<tick>),
- Word("_i", WordWrap<[] { *sp() = ((Word *)*sp())->immediate(); }, tobool>),
+ Word("_i", WordWrap<[] { *Forth.sp = ((Word *)*Forth.sp)->immediate(); }, tobool>),
Word("[']", WordWrap<tick, compileliteral>).markImmediate(),
Word("compile,", WordWrap<peek, commaSP>),
Word("word", WordWrap<word>),
Word("_b", WordWrap<[] {
std::putchar('#'); // Gives a good breakpoint spot for gdb
}>),
- Word(".", WordWrap<[] { std::cout << pop() << ' '; }>)
-);
+ Word(".", WordWrap<[] { std::cout << Forth.pop() << ' '; }>)
+};
void getinput()
{
@@ -100,13 +100,13 @@ void getinput()
int main()
{
- initialize(words);
+ std::for_each(words.begin(), words.end(), [](Word& w) { Forth.add(w); });
while (std::cin.good()) {
auto result = parse();
if (result == Error::none)
- std::cout << (STATE ? "compiled" : "ok") << std::endl;
+ std::cout << (Forth.state ? "compiled" : "ok") << std::endl;
else
std::cout << "error " << static_cast<int>(result) << std::endl;
}