]> code.bitgloo.com Git - clyne/sprit-forth.git/commitdiff
refactor, encapsulate main
authorClyne Sullivan <clyne@bitgloo.com>
Wed, 12 Jun 2024 10:55:37 +0000 (06:55 -0400)
committerClyne Sullivan <clyne@bitgloo.com>
Wed, 12 Jun 2024 10:55:37 +0000 (06:55 -0400)
Makefile
source/core.cpp
source/core.hpp
source/executor.cpp [new file with mode: 0644]
source/executor.hpp [new file with mode: 0644]
source/parse.cpp
source/parse.hpp
source/state.cpp
source/state.hpp
source/types.hpp
sprit.cpp

index 5b7f4866749e8d2cc3c7e5815495173167968d83..6d733e8753e20b80be46f024cf7bf44c68cb8f3b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 SRC := $(wildcard source/*.cpp)
 OBJ := $(subst .cpp,.o,$(SRC))
 
 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
 
            -Wall -Wextra -pedantic \
            -Isource
 
index e2da1093b77851c93184d036ed1a84ee9429833e..437c700a2c8e4151f4cf8d56dbfde6528bd44f4c 100644 (file)
@@ -1,5 +1,5 @@
 // sprit-forth: A portable subroutine-threaded Forth.
 // 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
 //
 // 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
 // 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
 
 #include "core.hpp"
 // 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
 
 #include "core.hpp"
-#include "state.hpp"
 
 #include <cctype>
 #include <cstring>
 
 
 #include <cctype>
 #include <cstring>
 
+static State state;
+
 void jump(FuncList ip)
 {
     // IP is incremented before its next execution.
 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()
 {
 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()
 {
 }
 
 bool haskey()
 {
-    return *((char *)&DICT[DIdxInBuf]) < DICT[DIdxSrcLen];
+    return Forth.sourcei < Forth.sourceu;
 }
 
 void addkey(int k)
 {
 }
 
 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);
 }
     auto ptr = reinterpret_cast<char *>(addr);
     *ptr = static_cast<char>(k);
 }
@@ -56,16 +55,16 @@ int key()
     while (!haskey())
         getinput();
 
     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)
 {
     return ptr[idx];
 }
 
 Cell *comma(Cell n)
 {
-    const auto ptr = reinterpret_cast<Cell *>(HERE);
+    const auto ptr = reinterpret_cast<Cell *>(Forth.here);
     *ptr = n;
     *ptr = n;
-    HERE += sizeof(Cell);
+    Forth.here += sizeof(Cell);
     return ptr;
 }
 
     return ptr;
 }
 
@@ -76,7 +75,7 @@ Addr aligned(Addr addr)
 
 void align()
 {
 
 void align()
 {
-    HERE = aligned(HERE);
+    Forth.here = aligned(Forth.here);
 }
 
 static void readword(int ch)
 }
 
 static void readword(int ch)
@@ -89,9 +88,9 @@ static void readword(int ch)
     // Collect the word's text.
     char *ptr;
     do {
     // Collect the word's text.
     char *ptr;
     do {
-        ptr = reinterpret_cast<char *>(HERE);
+        ptr = reinterpret_cast<char *>(Forth.here);
         *ptr = k;
         *ptr = k;
-        ++HERE;
+        ++Forth.here;
 
         if (!haskey())
             break;
 
         if (!haskey())
             break;
@@ -100,36 +99,37 @@ static void readword(int ch)
     } while (k != ch);
 
     // Add a null terminator.
     } while (k != ch);
 
     // Add a null terminator.
-    ptr = reinterpret_cast<char *>(HERE);
+    ptr = reinterpret_cast<char *>(Forth.here);
     *ptr = '\0';
     *ptr = '\0';
-    ++HERE;
+    ++Forth.here;
 }
 
 void word()
 {
 }
 
 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[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();
 }
 
 void colon()
 {
     // Collect (and store) the word's name.
     align();
-    auto name = HERE;
+    auto name = Forth.here;
     readword(' ');
     align();
 
     // Build the Word structure.
     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.
 
     // 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;
     // 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.
         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.
 
     // Enter compiling state.
-    STATE = -1;
+    Forth.compxt = *Forth.sp;
+    Forth.state = -1;
 }
 
 void semic()
 }
 
 void semic()
@@ -155,27 +154,26 @@ void semic()
     comma((Cell)fexit);
 
     // Complete the new word's linkage to make it usable.
     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.
 
     // Exit compilation state.
-    STATE = 0;
+    Forth.state = 0;
 }
 
 // TODO define in Forth? ": ' bl word find drop ;"
 void tick()
 {
     // Get the name to look up.
 }
 
 // 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.
     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`.
 
     // Deallocate `name`.
-    HERE = (Cell)name;
+    Forth.here = name;
 }
 
 }
 
index 8b220e4007cf79092ada0e14c0df648c8cae64c8..935fc0c982b286a38be9a0656d5a53efc84d1e08 100644 (file)
@@ -1,5 +1,5 @@
 // sprit-forth: A portable subroutine-threaded Forth.
 // 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
 //
 // 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
 
 #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.
 
 /**
  * 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<[] {
  * "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. */
 }>;
 
 void jump(FuncList ip); /** Jumps to the given instruction pointer. */
diff --git a/source/executor.cpp b/source/executor.cpp
new file mode 100644 (file)
index 0000000..d86abed
--- /dev/null
@@ -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 (file)
index 0000000..2029080
--- /dev/null
@@ -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
+
index 27c514d0eb63362822b4fde4139df164f98962c5..6e1d2bfa7bd14d60de012b4194691d5c9a209591 100644 (file)
@@ -1,5 +1,5 @@
 // sprit-forth: A portable subroutine-threaded Forth.
 // 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
 //
 // 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"
 // 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
 
 #include "core.hpp"
+#include "executor.hpp"
 #include "state.hpp"
 #include "types.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) {
     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 {
                 comma((Cell)word->list);
             } else {
-                result = execute1(word);
+                result = Exec.execute1(word);
             }
         } else if (isdigit(*start) || (*start == '-' && isdigit(*(start + 1)))) {
             }
         } 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;
                 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;
 static Error parseSource()
 {
     auto result = Error::none;
-    char *start = (char *)DICT[DIdxSource];
+    char *start = (char *)Forth.source;
     char *end = start;
     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;
         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);
             } else {
                 ++i; // discard the space
                 result = parseword(start, end);
-                start = (char *)DICT[DIdxSource] + i;
+                start = (char *)Forth.source + i;
                 end = start;
             }
         } else {
                 end = start;
             }
         } else {
@@ -85,9 +86,9 @@ static Error parseSource()
 Error parse()
 {
     // Reset source buffer and try to fill it with getinput().
 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');
 
     getinput();
     addkey('\0');
 
index 757cdae61aab1d237edae9314cbbb030952642da..0f97944e4c88082d538757f547e016ebf6385ec7 100644 (file)
@@ -1,5 +1,5 @@
 // sprit-forth: A portable subroutine-threaded Forth.
 // 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
 //
 // 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
index 03ad95d94664bbc1f472b5db9f291e2da68799f2..63c633a0448bcf5e10e22bf883a59f5bffb1008f 100644 (file)
@@ -1,5 +1,5 @@
 // sprit-forth: A portable subroutine-threaded Forth.
 // 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
 //
 // 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
 #include "core.hpp"
 #include "state.hpp"
 
 #include "core.hpp"
 #include "state.hpp"
 
-#include <csetjmp>
 #include <cstring>
 
 #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;
     }
         if (len == (int)strlen(w->name) && strncmp(s, w->name, len) == 0)
             return w;
     }
index b6e5bcf7759d3239b92769f2d80a2f69b141fa0e..5667875284a1f201fe490419fe1a3a69651b6d0c 100644 (file)
@@ -1,5 +1,5 @@
 // sprit-forth: A portable subroutine-threaded Forth.
 // 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
 //
 // 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);
 
 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
 
 
 #endif // STATE_HPP
 
index 0552135e147516bd25f8af1d8ce3879e6146f692..aedc0d39ccb231d133b30d335e7fd825d7fdc3a8 100644 (file)
@@ -1,5 +1,5 @@
 // sprit-forth: A portable subroutine-threaded Forth.
 // 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
 //
 // 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 <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. */
 
 using Cell = intptr_t;   /** Type of a dictionary's cell. */
 using Addr = uintptr_t;  /** Type of a dictionary address. */
@@ -33,6 +34,16 @@ using FuncList = Func const *; /** Words are defined as a list of Func. */
 static_assert(sizeof(Cell) == sizeof(Addr));
 static_assert(sizeof(Cell) == sizeof(Func));
 
 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.
 /**
  * @struct Word
  * @brief Structure of a word's definition.
@@ -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));
 
 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,
 enum class Error : int {
     none = 1,
     push,
index 7b36d2f4b339579aa8eeb2108b1c5a68d03a759d..faab0848007440a3c718cdb1a446d5b949447fa5 100644 (file)
--- a/sprit.cpp
+++ b/sprit.cpp
@@ -1,5 +1,5 @@
 // sprit-forth: A portable subroutine-threaded Forth.
 // 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
 //
 // 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
 // TODO:
 // sys m* _/ _% _' depth _rdepth _in _ev find _uma u< um/mod
 
 // 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("@",         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<[] {
     Word("_jmp0",     WordWrap<[] {
-        ++IP;
-        if (pop() == 0)
-            jump((FuncList)*IP);
+        ++Exec.ip;
+        if (Forth.pop() == 0)
+            jump((FuncList)*Exec.ip);
     }>),
     Word(",",         WordWrap<commaSP>),
     }>),
     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(":",         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("align",     WordWrap<align>),
-    Word("literal",   WordWrap<[] { if (STATE) compileliteral(); }>).markImmediate(),
+    Word("literal",   WordWrap<[] { if (Forth.state) compileliteral(); }>).markImmediate(),
     Word("\'",        WordWrap<tick>),
     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<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()
 {
 
 void getinput()
 {
@@ -100,13 +100,13 @@ void getinput()
 
 int main()
 {
 
 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)
 
     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;
     }
         else
             std::cout << "error " << static_cast<int>(result) << std::endl;
     }