]> code.bitgloo.com Git - bitgloo/alee-forth.git/commitdiff
move libalee into folder
authorClyne Sullivan <clyne@bitgloo.com>
Thu, 9 Mar 2023 00:57:26 +0000 (19:57 -0500)
committerClyne Sullivan <clyne@bitgloo.com>
Thu, 9 Mar 2023 00:57:26 +0000 (19:57 -0500)
22 files changed:
Makefile
alee.hpp
corewords.cpp [deleted file]
corewords.hpp [deleted file]
dictionary.cpp [deleted file]
dictionary.hpp [deleted file]
libalee/corewords.cpp [new file with mode: 0644]
libalee/corewords.hpp [new file with mode: 0644]
libalee/dictionary.cpp [new file with mode: 0644]
libalee/dictionary.hpp [new file with mode: 0644]
libalee/parser.cpp [new file with mode: 0644]
libalee/parser.hpp [new file with mode: 0644]
libalee/state.cpp [new file with mode: 0644]
libalee/state.hpp [new file with mode: 0644]
libalee/types.hpp [new file with mode: 0644]
memdict.hpp
parser.cpp [deleted file]
parser.hpp [deleted file]
splitmemdict.hpp
state.cpp [deleted file]
state.hpp [deleted file]
types.hpp [deleted file]

index 86df6a6238aa2260b6eddc946e9d6377da57a3c7..5e75d76f2df2b5398c42d93c59c1c49a76bb2363 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,9 +2,9 @@ CXXFLAGS += -std=c++17 -g3 -ggdb -O0 \
             -Wall -Wextra -pedantic -Werror \
             -fno-exceptions -fno-rtti #-fstack-usage
 
-CXXFILES := corewords.cpp dictionary.cpp parser.cpp state.cpp
+CXXFILES := $(wildcard libalee/*.cpp)
 OBJFILES := $(subst .cpp,.o,$(CXXFILES))
-LIBFILE := libalee.a
+LIBFILE := libalee/libalee.a
 
 all: alee
 
index f091cf84100637d6e70c4b5476e630a63bb8c5a5..87991bbfeb7407be7ec40b277108ced46bdce82f 100644 (file)
--- a/alee.hpp
+++ b/alee.hpp
@@ -1,3 +1,3 @@
-#include "parser.hpp"
-#include "state.hpp"
+#include "libalee/parser.hpp"
+#include "libalee/state.hpp"
 
diff --git a/corewords.cpp b/corewords.cpp
deleted file mode 100644 (file)
index 4de9413..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-/**
- * Alee Forth: A portable and concise Forth implementation in modern C++.
- * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "corewords.hpp"
-
-#include <cstring>
-#include <utility>
-
-Word getword(State& state)
-{
-    auto word = state.dict.input();
-    while (word.size() == 0) {
-        state.input(state);
-        word = state.dict.input();
-    }
-    return word;
-}
-void newdef(State& state, Word word)
-{
-    auto& dict = state.dict;
-
-    auto addr = dict.alignhere();
-    dict.addDefinition(word);
-    state.push(addr);
-};
-void tick(State& state)
-{
-    auto word = getword(state);
-    if (auto j = state.dict.find(word); j > 0) {
-        state.push(state.dict.getexec(j));
-        auto imm = state.dict.read(j) & CoreWords::Immediate;
-        state.push(imm ? 1 : -1);
-    } else if (auto i = CoreWords::findi(state, word); i >= 0) {
-        state.push(i);
-        state.push(i == CoreWords::Semicolon ? 1 : -1);
-    } else {
-        state.push(0);
-        state.push(0);
-    }
-}
-
-void CoreWords::run(unsigned int index, State& state)
-{
-    Cell cell;
-    DoubleCell dcell;
-
-execute:
-    if (/*(index & 1) == 0 &&*/ index >= WordCount) {
-        // must be calling a defined subroutine
-        state.pushr(state.ip);
-        state.ip = index;
-        return;
-    } else switch (index & 0x1F) {
-    case 0: // _lit
-        state.push(/*(index & 0xFF00) ? ((Addr)index >> 8u) - 1 :*/ state.beyondip());
-        break;
-    case 1: // drop
-        state.pop();
-        break;
-    case 2: // dup
-        state.push(state.top());
-        break;
-    case 3: // swap
-        std::swap(state.top(), state.pick(1));
-        break;
-    case 4: // pick
-        state.push(state.pick(state.pop()));
-        break;
-    case 5: // sys
-        user_sys(state);
-        break;
-    case 6: // add
-        cell = state.pop();
-        state.top() += cell;
-        break;
-    case 7: // sub
-        cell = state.pop();
-        state.top() -= cell;
-        break;
-    case 8: // mul ( n n -- d )
-        cell = state.pop();
-        dcell = state.pop() * cell;
-        state.push(dcell);
-        state.push(dcell >> (sizeof(Cell) * 8));
-        break;
-    case 9: // div ( d n -- n )
-        cell = state.pop();
-        dcell = state.pop();
-        dcell <<= sizeof(Cell) * 8;
-        dcell |= static_cast<Addr>(state.pop());
-        state.push(dcell / cell);
-        break;
-    case 10: // mod ( d n -- n )
-        cell = state.pop();
-        dcell = state.pop();
-        dcell <<= sizeof(Cell) * 8;
-        dcell |= static_cast<Addr>(state.pop());
-        state.push(dcell % cell);
-        break;
-    case 11: // peek
-        if (state.pop())
-            state.push(state.dict.read(state.pop()));
-        else
-            state.push(state.dict.readbyte(state.pop()));
-        break;
-    case 12: // poke
-        cell = state.pop();
-        if (auto addr = state.pop(); cell)
-            state.dict.write(addr, state.pop());
-        else
-            state.dict.writebyte(addr, state.pop());
-        break;
-    case 13: // pushr
-        state.pushr(state.pop());
-        break;
-    case 14: // popr
-        state.push(state.popr());
-        break;
-    case 15: // equal
-        cell = state.pop();
-        state.top() = state.top() == cell ? -1 : 0;
-        break;
-    case 16: // lt
-        cell = state.pop();
-        state.top() = state.top() < cell ? -1 : 0;
-        break;
-    case 17: // and
-        cell = state.pop();
-        state.top() &= cell;
-        break;
-    case 18: // or
-        cell = state.pop();
-        state.top() |= cell;
-        break;
-    case 19: // xor
-        cell = state.pop();
-        state.top() ^= cell;
-        break;
-    case 20: // shl
-        cell = state.pop();
-        reinterpret_cast<Addr&>(state.top()) <<= static_cast<Addr>(cell);
-        break;
-    case 21: // shr
-        cell = state.pop();
-        reinterpret_cast<Addr&>(state.top()) >>= static_cast<Addr>(cell);
-        break;
-    case 22: // colon
-        newdef(state, getword(state));
-        state.compiling(true);
-        break;
-    case 23: // tick
-        tick(state);
-        break;
-    case 24: // execute
-        index = state.pop();
-        goto execute;
-    case 25: // exit
-        state.ip = state.popr();
-        if (state.ip == 0) {
-            std::longjmp(state.jmpbuf,
-                static_cast<int>(State::Error::exit));
-        }
-        break;
-    case 26: // semic
-        {
-        state.dict.add(findi("exit"));
-        state.compiling(false);
-
-        auto addr = state.pop();
-        state.dict.write(addr,
-            (state.dict.read(addr) & 0x1F) |
-            ((addr - state.dict.latest()) << 6));
-        state.dict.latest(addr);
-        }
-        break;
-    case 27: // _jmp0
-        if (state.pop()) {
-            state.beyondip();
-            break;
-        }
-        [[fallthrough]];
-    case 28: // _jmp
-        state.ip = state.beyondip();
-        return;
-    case 29: // depth
-        state.push(state.size());
-        break;
-    case 30: // _rdepth
-        state.push(state.rsize());
-        break;
-    case 31: // _in
-        state.input(state);
-        break;
-    }
-
-    state.ip += sizeof(Cell);
-}
-
-int CoreWords::findi(const char *word)
-{
-    std::size_t i = 0;
-    int wordsi = 0;
-
-    while (i < sizeof(wordsarr)) {
-        auto end = i;
-        while (wordsarr[end])
-            ++end;
-
-        if (!std::strcmp(word, wordsarr + i))
-            return wordsi;
-
-        ++wordsi;
-        i = end + 1;
-    }
-
-    return -1;
-}
-
-int CoreWords::findi(State& state, Word word)
-{
-    std::size_t i = 0;
-    int wordsi = 0;
-
-    while (i < sizeof(wordsarr)) {
-        auto end = i;
-        while (wordsarr[end])
-            ++end;
-
-        if (state.dict.equal(word, wordsarr + i, end - i))
-            return wordsi;
-
-        ++wordsi;
-        i = end + 1;
-    }
-
-    return -1;
-}
-
diff --git a/corewords.hpp b/corewords.hpp
deleted file mode 100644 (file)
index 21a0951..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * Alee Forth: A portable and concise Forth implementation in modern C++.
- * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-#ifndef ALEEFORTH_COREWORDS_HPP
-#define ALEEFORTH_COREWORDS_HPP
-
-#include "types.hpp"
-#include "state.hpp"
-
-void user_sys(State&);
-
-class CoreWords
-{
-public:
-    constexpr static std::size_t WordCount = 32;
-
-    constexpr static Cell Immediate = (1 << 5);
-
-    constexpr static int Semicolon = 26;
-
-    static int findi(const char *);
-    static int findi(State&, Word);
-    static void run(unsigned int, State&);
-
-private:
-    constexpr static char wordsarr[] =
-        "_lit\0drop\0dup\0swap\0pick\0sys\0"
-        "+\0-\0m*\0_/\0_%\0"
-        "_@\0_!\0>r\0r>\0=\0"
-        "<\0&\0|\0^\0"
-        "<<\0>>\0:\0_'\0execute\0"
-        "exit\0;\0_jmp0\0_jmp\0"
-        "depth\0_rdepth\0_in\0";
-};
-
-#endif // ALEEFORTH_COREWORDS_HPP
-
diff --git a/dictionary.cpp b/dictionary.cpp
deleted file mode 100644 (file)
index 48230c4..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/**
- * Alee Forth: A portable and concise Forth implementation in modern C++.
- * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "dictionary.hpp"
-
-#include <cctype>
-#include <cstring>
-
-void Dictionary::initialize()
-{
-    write(Base, 10);
-    write(Here, Begin);
-    write(Latest, Begin);
-    write(Compiling, 0);
-    write(Source, Input + sizeof(Cell));
-}
-
-Addr Dictionary::allot(Cell amount) noexcept
-{
-    Addr old = here();
-    here(old + amount);
-    return old;
-}
-
-void Dictionary::add(Cell value) noexcept
-{
-    write(allot(sizeof(Cell)), value);
-}
-
-Addr Dictionary::aligned(Addr addr) const noexcept
-{
-    auto unaligned = addr & (sizeof(Cell) - sizeof(uint8_t));
-    if (unaligned)
-        addr += sizeof(Cell) - unaligned;
-
-    return addr;
-}
-
-Addr Dictionary::alignhere() noexcept
-{
-    here(aligned(here()));
-    return here();
-}
-
-void Dictionary::addDefinition(Word word) noexcept
-{
-    add(word.size());
-    for (auto w = word.start; w != word.end; ++w)
-        writebyte(allot(1), readbyte(w));
-
-    alignhere();
-}
-
-Addr Dictionary::find(Word word) noexcept
-{
-    Addr lt = latest(), oldlt;
-    do {
-        oldlt = lt;
-        const auto l = static_cast<Addr>(read(lt));
-        const Addr len = l & 0x1F;
-        const Word lw {
-            static_cast<Addr>(lt + sizeof(Cell)),
-            static_cast<Addr>(lt + sizeof(Cell) + len)
-        };
-
-        if (equal(word, lw))
-            return lt;
-        else
-            lt -= l >> 6;
-    } while (lt != oldlt);
-
-    return 0;
-}
-
-Addr Dictionary::getexec(Addr addr) noexcept
-{
-    const auto len = read(addr) & 0x1F;
-    return aligned(addr + sizeof(Cell) + len);
-}
-
-Word Dictionary::input() noexcept
-{
-    auto src = read(Dictionary::Source);
-    auto end = read(Dictionary::SourceLen);
-    auto idx = read(Dictionary::Input);
-
-    Addr wordstart = src + idx;
-    Addr wordend = wordstart;
-
-    while (idx < end) {
-        auto ch = readbyte(wordend);
-
-        if (ch == '\0')
-            break;
-
-        if (isspace(ch)) {
-            if (wordstart != wordend) {
-                writebyte(Dictionary::Input, idx + 1);
-                return {wordstart, wordend};
-            }
-
-            ++wordstart;
-        }
-
-        ++wordend;
-        ++idx;
-    }
-
-    if (wordstart != wordend) {
-        writebyte(Dictionary::Input, idx + 1);
-        return {wordstart, wordend};
-    }
-
-    return {};
-}
-
-bool Dictionary::equal(Word word, const char *str, unsigned len) const noexcept
-{
-    if (word.size() != len)
-        return false;
-
-    for (auto w = word.start; w != word.end; ++w) {
-        auto wc = readbyte(w);
-        if (wc != *str) {
-            if (isalpha(wc) && isalpha(*str) && (wc | 32) == (*str | 32)) {
-                ++str;
-                continue;
-            }
-
-            return false;
-        }
-
-        ++str;
-    }
-
-    return true;
-}
-
-bool Dictionary::equal(Word word, Word other) const noexcept
-{
-    if (word.size() != other.size())
-        return false;
-
-    auto w = word.start, o = other.start;
-    while (w != word.end) {
-        auto wc = readbyte(w), oc = readbyte(o);
-        if (wc != oc) {
-            if (isalpha(wc) && isalpha(oc) && (wc | 32) == (oc | 32)) {
-                ++w, ++o;
-                continue;
-            }
-
-            return false;
-        }
-
-        ++w, ++o;
-    }
-
-    return true;
-}
-
diff --git a/dictionary.hpp b/dictionary.hpp
deleted file mode 100644 (file)
index 4dcae77..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * Alee Forth: A portable and concise Forth implementation in modern C++.
- * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-#ifndef ALEEFORTH_DICTIONARY_HPP
-#define ALEEFORTH_DICTIONARY_HPP
-
-#include "types.hpp"
-
-#include <cstddef>
-#include <cstdint>
-
-/**
- * Dictionary entry format:
- *  - 1 information byte
- *    bits  0..4: Length of name (L)
- *    bit      5: Immediate?
- *    bits 6..15: Distance to next entry (negative)
- *  - L bytes of name
- *  - 0+ bytes for address alignment
- *  - 0+ bytes of entry's data...
- */
-
-class Dictionary
-{
-public:
-    constexpr static Addr Base       = 0;
-    constexpr static Addr Here       = sizeof(Cell);
-    constexpr static Addr Latest     = sizeof(Cell) * 2;
-    constexpr static Addr Compiling  = sizeof(Cell) * 3;
-    constexpr static Addr Source     = sizeof(Cell) * 4;
-    constexpr static Addr SourceLen  = sizeof(Cell) * 5;
-    constexpr static Addr Input      = sizeof(Cell) * 6; // len data...
-    constexpr static Addr InputCells = 80; // bytes!
-    constexpr static Addr Begin      = sizeof(Cell) * 7 + InputCells;
-
-    void initialize();
-
-    Addr here() const noexcept { return read(Here); }
-    void here(Addr l) noexcept { write(Here, l); }
-
-    Addr latest() const noexcept { return read(Latest); }
-    void latest(Addr l) noexcept { write(Latest, l); }
-
-    virtual Cell read(Addr) const noexcept = 0;
-    virtual void write(Addr, Cell) noexcept = 0;
-    virtual uint8_t readbyte(Addr) const noexcept = 0;
-    virtual void writebyte(Addr, uint8_t) noexcept = 0;
-
-    Addr alignhere() noexcept;
-    Addr aligned(Addr) const noexcept;
-    Addr allot(Cell) noexcept;
-    void add(Cell) noexcept;
-    void addDefinition(Word) noexcept;
-
-    Addr find(Word) noexcept;
-    Addr getexec(Addr) noexcept;
-    Word input() noexcept;
-
-    bool equal(Word, const char *, unsigned) const noexcept;
-    bool equal(Word, Word) const noexcept;
-};
-
-#endif // ALEEFORTH_DICTIONARY_HPP
-
diff --git a/libalee/corewords.cpp b/libalee/corewords.cpp
new file mode 100644 (file)
index 0000000..4de9413
--- /dev/null
@@ -0,0 +1,253 @@
+/**
+ * Alee Forth: A portable and concise Forth implementation in modern C++.
+ * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "corewords.hpp"
+
+#include <cstring>
+#include <utility>
+
+Word getword(State& state)
+{
+    auto word = state.dict.input();
+    while (word.size() == 0) {
+        state.input(state);
+        word = state.dict.input();
+    }
+    return word;
+}
+void newdef(State& state, Word word)
+{
+    auto& dict = state.dict;
+
+    auto addr = dict.alignhere();
+    dict.addDefinition(word);
+    state.push(addr);
+};
+void tick(State& state)
+{
+    auto word = getword(state);
+    if (auto j = state.dict.find(word); j > 0) {
+        state.push(state.dict.getexec(j));
+        auto imm = state.dict.read(j) & CoreWords::Immediate;
+        state.push(imm ? 1 : -1);
+    } else if (auto i = CoreWords::findi(state, word); i >= 0) {
+        state.push(i);
+        state.push(i == CoreWords::Semicolon ? 1 : -1);
+    } else {
+        state.push(0);
+        state.push(0);
+    }
+}
+
+void CoreWords::run(unsigned int index, State& state)
+{
+    Cell cell;
+    DoubleCell dcell;
+
+execute:
+    if (/*(index & 1) == 0 &&*/ index >= WordCount) {
+        // must be calling a defined subroutine
+        state.pushr(state.ip);
+        state.ip = index;
+        return;
+    } else switch (index & 0x1F) {
+    case 0: // _lit
+        state.push(/*(index & 0xFF00) ? ((Addr)index >> 8u) - 1 :*/ state.beyondip());
+        break;
+    case 1: // drop
+        state.pop();
+        break;
+    case 2: // dup
+        state.push(state.top());
+        break;
+    case 3: // swap
+        std::swap(state.top(), state.pick(1));
+        break;
+    case 4: // pick
+        state.push(state.pick(state.pop()));
+        break;
+    case 5: // sys
+        user_sys(state);
+        break;
+    case 6: // add
+        cell = state.pop();
+        state.top() += cell;
+        break;
+    case 7: // sub
+        cell = state.pop();
+        state.top() -= cell;
+        break;
+    case 8: // mul ( n n -- d )
+        cell = state.pop();
+        dcell = state.pop() * cell;
+        state.push(dcell);
+        state.push(dcell >> (sizeof(Cell) * 8));
+        break;
+    case 9: // div ( d n -- n )
+        cell = state.pop();
+        dcell = state.pop();
+        dcell <<= sizeof(Cell) * 8;
+        dcell |= static_cast<Addr>(state.pop());
+        state.push(dcell / cell);
+        break;
+    case 10: // mod ( d n -- n )
+        cell = state.pop();
+        dcell = state.pop();
+        dcell <<= sizeof(Cell) * 8;
+        dcell |= static_cast<Addr>(state.pop());
+        state.push(dcell % cell);
+        break;
+    case 11: // peek
+        if (state.pop())
+            state.push(state.dict.read(state.pop()));
+        else
+            state.push(state.dict.readbyte(state.pop()));
+        break;
+    case 12: // poke
+        cell = state.pop();
+        if (auto addr = state.pop(); cell)
+            state.dict.write(addr, state.pop());
+        else
+            state.dict.writebyte(addr, state.pop());
+        break;
+    case 13: // pushr
+        state.pushr(state.pop());
+        break;
+    case 14: // popr
+        state.push(state.popr());
+        break;
+    case 15: // equal
+        cell = state.pop();
+        state.top() = state.top() == cell ? -1 : 0;
+        break;
+    case 16: // lt
+        cell = state.pop();
+        state.top() = state.top() < cell ? -1 : 0;
+        break;
+    case 17: // and
+        cell = state.pop();
+        state.top() &= cell;
+        break;
+    case 18: // or
+        cell = state.pop();
+        state.top() |= cell;
+        break;
+    case 19: // xor
+        cell = state.pop();
+        state.top() ^= cell;
+        break;
+    case 20: // shl
+        cell = state.pop();
+        reinterpret_cast<Addr&>(state.top()) <<= static_cast<Addr>(cell);
+        break;
+    case 21: // shr
+        cell = state.pop();
+        reinterpret_cast<Addr&>(state.top()) >>= static_cast<Addr>(cell);
+        break;
+    case 22: // colon
+        newdef(state, getword(state));
+        state.compiling(true);
+        break;
+    case 23: // tick
+        tick(state);
+        break;
+    case 24: // execute
+        index = state.pop();
+        goto execute;
+    case 25: // exit
+        state.ip = state.popr();
+        if (state.ip == 0) {
+            std::longjmp(state.jmpbuf,
+                static_cast<int>(State::Error::exit));
+        }
+        break;
+    case 26: // semic
+        {
+        state.dict.add(findi("exit"));
+        state.compiling(false);
+
+        auto addr = state.pop();
+        state.dict.write(addr,
+            (state.dict.read(addr) & 0x1F) |
+            ((addr - state.dict.latest()) << 6));
+        state.dict.latest(addr);
+        }
+        break;
+    case 27: // _jmp0
+        if (state.pop()) {
+            state.beyondip();
+            break;
+        }
+        [[fallthrough]];
+    case 28: // _jmp
+        state.ip = state.beyondip();
+        return;
+    case 29: // depth
+        state.push(state.size());
+        break;
+    case 30: // _rdepth
+        state.push(state.rsize());
+        break;
+    case 31: // _in
+        state.input(state);
+        break;
+    }
+
+    state.ip += sizeof(Cell);
+}
+
+int CoreWords::findi(const char *word)
+{
+    std::size_t i = 0;
+    int wordsi = 0;
+
+    while (i < sizeof(wordsarr)) {
+        auto end = i;
+        while (wordsarr[end])
+            ++end;
+
+        if (!std::strcmp(word, wordsarr + i))
+            return wordsi;
+
+        ++wordsi;
+        i = end + 1;
+    }
+
+    return -1;
+}
+
+int CoreWords::findi(State& state, Word word)
+{
+    std::size_t i = 0;
+    int wordsi = 0;
+
+    while (i < sizeof(wordsarr)) {
+        auto end = i;
+        while (wordsarr[end])
+            ++end;
+
+        if (state.dict.equal(word, wordsarr + i, end - i))
+            return wordsi;
+
+        ++wordsi;
+        i = end + 1;
+    }
+
+    return -1;
+}
+
diff --git a/libalee/corewords.hpp b/libalee/corewords.hpp
new file mode 100644 (file)
index 0000000..21a0951
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+ * Alee Forth: A portable and concise Forth implementation in modern C++.
+ * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALEEFORTH_COREWORDS_HPP
+#define ALEEFORTH_COREWORDS_HPP
+
+#include "types.hpp"
+#include "state.hpp"
+
+void user_sys(State&);
+
+class CoreWords
+{
+public:
+    constexpr static std::size_t WordCount = 32;
+
+    constexpr static Cell Immediate = (1 << 5);
+
+    constexpr static int Semicolon = 26;
+
+    static int findi(const char *);
+    static int findi(State&, Word);
+    static void run(unsigned int, State&);
+
+private:
+    constexpr static char wordsarr[] =
+        "_lit\0drop\0dup\0swap\0pick\0sys\0"
+        "+\0-\0m*\0_/\0_%\0"
+        "_@\0_!\0>r\0r>\0=\0"
+        "<\0&\0|\0^\0"
+        "<<\0>>\0:\0_'\0execute\0"
+        "exit\0;\0_jmp0\0_jmp\0"
+        "depth\0_rdepth\0_in\0";
+};
+
+#endif // ALEEFORTH_COREWORDS_HPP
+
diff --git a/libalee/dictionary.cpp b/libalee/dictionary.cpp
new file mode 100644 (file)
index 0000000..48230c4
--- /dev/null
@@ -0,0 +1,176 @@
+/**
+ * Alee Forth: A portable and concise Forth implementation in modern C++.
+ * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "dictionary.hpp"
+
+#include <cctype>
+#include <cstring>
+
+void Dictionary::initialize()
+{
+    write(Base, 10);
+    write(Here, Begin);
+    write(Latest, Begin);
+    write(Compiling, 0);
+    write(Source, Input + sizeof(Cell));
+}
+
+Addr Dictionary::allot(Cell amount) noexcept
+{
+    Addr old = here();
+    here(old + amount);
+    return old;
+}
+
+void Dictionary::add(Cell value) noexcept
+{
+    write(allot(sizeof(Cell)), value);
+}
+
+Addr Dictionary::aligned(Addr addr) const noexcept
+{
+    auto unaligned = addr & (sizeof(Cell) - sizeof(uint8_t));
+    if (unaligned)
+        addr += sizeof(Cell) - unaligned;
+
+    return addr;
+}
+
+Addr Dictionary::alignhere() noexcept
+{
+    here(aligned(here()));
+    return here();
+}
+
+void Dictionary::addDefinition(Word word) noexcept
+{
+    add(word.size());
+    for (auto w = word.start; w != word.end; ++w)
+        writebyte(allot(1), readbyte(w));
+
+    alignhere();
+}
+
+Addr Dictionary::find(Word word) noexcept
+{
+    Addr lt = latest(), oldlt;
+    do {
+        oldlt = lt;
+        const auto l = static_cast<Addr>(read(lt));
+        const Addr len = l & 0x1F;
+        const Word lw {
+            static_cast<Addr>(lt + sizeof(Cell)),
+            static_cast<Addr>(lt + sizeof(Cell) + len)
+        };
+
+        if (equal(word, lw))
+            return lt;
+        else
+            lt -= l >> 6;
+    } while (lt != oldlt);
+
+    return 0;
+}
+
+Addr Dictionary::getexec(Addr addr) noexcept
+{
+    const auto len = read(addr) & 0x1F;
+    return aligned(addr + sizeof(Cell) + len);
+}
+
+Word Dictionary::input() noexcept
+{
+    auto src = read(Dictionary::Source);
+    auto end = read(Dictionary::SourceLen);
+    auto idx = read(Dictionary::Input);
+
+    Addr wordstart = src + idx;
+    Addr wordend = wordstart;
+
+    while (idx < end) {
+        auto ch = readbyte(wordend);
+
+        if (ch == '\0')
+            break;
+
+        if (isspace(ch)) {
+            if (wordstart != wordend) {
+                writebyte(Dictionary::Input, idx + 1);
+                return {wordstart, wordend};
+            }
+
+            ++wordstart;
+        }
+
+        ++wordend;
+        ++idx;
+    }
+
+    if (wordstart != wordend) {
+        writebyte(Dictionary::Input, idx + 1);
+        return {wordstart, wordend};
+    }
+
+    return {};
+}
+
+bool Dictionary::equal(Word word, const char *str, unsigned len) const noexcept
+{
+    if (word.size() != len)
+        return false;
+
+    for (auto w = word.start; w != word.end; ++w) {
+        auto wc = readbyte(w);
+        if (wc != *str) {
+            if (isalpha(wc) && isalpha(*str) && (wc | 32) == (*str | 32)) {
+                ++str;
+                continue;
+            }
+
+            return false;
+        }
+
+        ++str;
+    }
+
+    return true;
+}
+
+bool Dictionary::equal(Word word, Word other) const noexcept
+{
+    if (word.size() != other.size())
+        return false;
+
+    auto w = word.start, o = other.start;
+    while (w != word.end) {
+        auto wc = readbyte(w), oc = readbyte(o);
+        if (wc != oc) {
+            if (isalpha(wc) && isalpha(oc) && (wc | 32) == (oc | 32)) {
+                ++w, ++o;
+                continue;
+            }
+
+            return false;
+        }
+
+        ++w, ++o;
+    }
+
+    return true;
+}
+
diff --git a/libalee/dictionary.hpp b/libalee/dictionary.hpp
new file mode 100644 (file)
index 0000000..4dcae77
--- /dev/null
@@ -0,0 +1,79 @@
+/**
+ * Alee Forth: A portable and concise Forth implementation in modern C++.
+ * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALEEFORTH_DICTIONARY_HPP
+#define ALEEFORTH_DICTIONARY_HPP
+
+#include "types.hpp"
+
+#include <cstddef>
+#include <cstdint>
+
+/**
+ * Dictionary entry format:
+ *  - 1 information byte
+ *    bits  0..4: Length of name (L)
+ *    bit      5: Immediate?
+ *    bits 6..15: Distance to next entry (negative)
+ *  - L bytes of name
+ *  - 0+ bytes for address alignment
+ *  - 0+ bytes of entry's data...
+ */
+
+class Dictionary
+{
+public:
+    constexpr static Addr Base       = 0;
+    constexpr static Addr Here       = sizeof(Cell);
+    constexpr static Addr Latest     = sizeof(Cell) * 2;
+    constexpr static Addr Compiling  = sizeof(Cell) * 3;
+    constexpr static Addr Source     = sizeof(Cell) * 4;
+    constexpr static Addr SourceLen  = sizeof(Cell) * 5;
+    constexpr static Addr Input      = sizeof(Cell) * 6; // len data...
+    constexpr static Addr InputCells = 80; // bytes!
+    constexpr static Addr Begin      = sizeof(Cell) * 7 + InputCells;
+
+    void initialize();
+
+    Addr here() const noexcept { return read(Here); }
+    void here(Addr l) noexcept { write(Here, l); }
+
+    Addr latest() const noexcept { return read(Latest); }
+    void latest(Addr l) noexcept { write(Latest, l); }
+
+    virtual Cell read(Addr) const noexcept = 0;
+    virtual void write(Addr, Cell) noexcept = 0;
+    virtual uint8_t readbyte(Addr) const noexcept = 0;
+    virtual void writebyte(Addr, uint8_t) noexcept = 0;
+
+    Addr alignhere() noexcept;
+    Addr aligned(Addr) const noexcept;
+    Addr allot(Cell) noexcept;
+    void add(Cell) noexcept;
+    void addDefinition(Word) noexcept;
+
+    Addr find(Word) noexcept;
+    Addr getexec(Addr) noexcept;
+    Word input() noexcept;
+
+    bool equal(Word, const char *, unsigned) const noexcept;
+    bool equal(Word, Word) const noexcept;
+};
+
+#endif // ALEEFORTH_DICTIONARY_HPP
+
diff --git a/libalee/parser.cpp b/libalee/parser.cpp
new file mode 100644 (file)
index 0000000..44b5cec
--- /dev/null
@@ -0,0 +1,112 @@
+/**
+ * Alee Forth: A portable and concise Forth implementation in modern C++.
+ * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "corewords.hpp"
+#include "parser.hpp"
+
+#include <charconv>
+#include <cstring>
+
+int Parser::parse(State& state, const char *str)
+{
+    auto addr = Dictionary::Input;
+    state.dict.write(addr, 0);
+    state.dict.write(Dictionary::SourceLen, std::strlen(str));
+
+    addr += sizeof(Cell);
+    while (*str)
+        state.dict.writebyte(addr++, *str++);
+
+    while (addr < Dictionary::Input + Dictionary::InputCells)
+        state.dict.writebyte(addr++, '\0');
+
+    return parseSource(state);
+}
+
+int Parser::parseSource(State& state)
+{
+    auto word = state.dict.input();
+    while (word.size() > 0) {
+        if (auto ret = parseWord(state, word); ret)
+            return ret;
+
+        word = state.dict.input();
+    }
+
+    return 0;
+}
+
+int Parser::parseWord(State& state, Word word)
+{
+    int ins, imm;
+
+    ins = state.dict.find(word);
+
+    if (ins <= 0) {
+        ins = CoreWords::findi(state, word);
+
+        if (ins < 0)
+            return parseNumber(state, word);
+        else
+            imm = ins == CoreWords::Semicolon;
+    } else {
+        imm = state.dict.read(ins) & CoreWords::Immediate;
+        ins = state.dict.getexec(ins);
+    }
+
+    if (state.compiling() && !imm)
+        state.dict.add(ins);
+    else if (auto stat = state.execute(ins); stat != State::Error::none)
+        return static_cast<int>(stat);
+
+    return 0;
+}
+
+int Parser::parseNumber(State& state, Word word)
+{
+    char buf[MaxCellNumberChars + 1];
+    unsigned i;
+    for (i = 0; i < std::min(MaxCellNumberChars, word.size()); ++i)
+        buf[i] = state.dict.readbyte(word.start + i);
+    buf[i] = '\0';
+
+    auto base = state.dict.read(0);
+    DoubleCell dl;
+    auto [ptr, ec] = std::from_chars(buf, buf + i, dl, base);
+    Cell l = static_cast<Cell>(dl);
+
+    if (ec == std::errc() && ptr == buf + i) {
+        if (state.compiling()) {
+            auto ins = CoreWords::findi("_lit");
+
+            //if (l >= 0 && l < 0xFF) {
+            //    state.dict.add(ins | ((l + 1) << 8));
+            //} else {
+                state.dict.add(ins);
+                state.dict.add(l);
+            //}
+        } else {
+            state.push(l);
+        }
+
+        return 0;
+    } else {
+        return UnknownWord;
+    }
+}
+
diff --git a/libalee/parser.hpp b/libalee/parser.hpp
new file mode 100644 (file)
index 0000000..4b14d64
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+ * Alee Forth: A portable and concise Forth implementation in modern C++.
+ * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALEEFORTH_PARSER_HPP
+#define ALEEFORTH_PARSER_HPP
+
+#include "types.hpp"
+
+#include <string_view>
+
+class Parser
+{
+public:
+    constexpr static int UnknownWord = -1;
+
+    int parse(State&, const char *);
+    int parseSource(State&);
+
+private:
+    int parseWord(State&, Word);
+    int parseNumber(State&, Word);
+};
+
+#endif // ALEEFORTH_PARSER_HPP
+
diff --git a/libalee/state.cpp b/libalee/state.cpp
new file mode 100644 (file)
index 0000000..ea6c601
--- /dev/null
@@ -0,0 +1,65 @@
+/**
+ * Alee Forth: A portable and concise Forth implementation in modern C++.
+ * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "corewords.hpp"
+#include "state.hpp"
+
+#include <iterator>
+
+bool State::compiling() const
+{
+    return dict.read(Dictionary::Compiling);
+}
+
+void State::compiling(bool yes)
+{
+    dict.write(Dictionary::Compiling, yes);
+}
+
+State::Error State::execute(Addr addr)
+{
+    auto stat = static_cast<State::Error>(setjmp(jmpbuf));
+
+    if (stat == State::Error::none) {
+        CoreWords::run(addr, *this);
+
+        if (ip >= Dictionary::Begin) {
+            // longjmp will exit this loop.
+            for (;;)
+                CoreWords::run(dict.read(ip), *this);
+        } else {
+            // addr was a CoreWord, all done now.
+            ip = 0;
+        }
+    } else if (stat == State::Error::exit) {
+        stat = State::Error::none;
+    }
+
+    return stat;
+}
+
+std::size_t State::size() const noexcept
+{
+    return std::distance(dstack, static_cast<const Cell *>(dsp)) + 1;
+}
+
+std::size_t State::rsize() const noexcept
+{
+    return std::distance(rstack, static_cast<const Cell *>(rsp)) + 1;
+}
+
diff --git a/libalee/state.hpp b/libalee/state.hpp
new file mode 100644 (file)
index 0000000..28396dc
--- /dev/null
@@ -0,0 +1,109 @@
+/**
+ * Alee Forth: A portable and concise Forth implementation in modern C++.
+ * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALEEFORTH_STATE_HPP
+#define ALEEFORTH_STATE_HPP
+
+#include "dictionary.hpp"
+#include "types.hpp"
+
+#include <csetjmp>
+#include <cstddef>
+
+constexpr unsigned DataStackSize = 16;
+constexpr unsigned ReturnStackSize = 16;
+
+struct State
+{
+    enum class Error : int {
+        none = 0,
+        push,
+        pop,
+        pushr,
+        popr,
+        top,
+        pick,
+        exit
+    };
+
+    Addr ip = 0;
+    Dictionary& dict;
+    void (*input)(State&);
+
+    Cell dstack[DataStackSize] = {};
+    Cell rstack[ReturnStackSize] = {};
+    Cell *dsp = dstack - 1;
+    Cell *rsp = rstack - 1;
+
+    std::jmp_buf jmpbuf = {};
+
+    constexpr State(Dictionary& d, void (*i)(State&)):
+        dict(d), input(i) {}
+
+    bool compiling() const;
+    void compiling(bool);
+
+    Error execute(Addr);
+
+    std::size_t size() const noexcept;
+    std::size_t rsize() const noexcept;
+
+    inline void push(Cell value) {
+        if (dsp == dstack + DataStackSize - 1)
+            std::longjmp(jmpbuf, static_cast<int>(Error::push));
+        *++dsp = value;
+    }
+
+    inline Cell pop() {
+        if (dsp < dstack)
+            std::longjmp(jmpbuf, static_cast<int>(Error::pop));
+        return *dsp--;
+    }
+
+    inline Cell beyondip() {
+        ip += sizeof(Cell);
+        return dict.read(ip);
+    }
+
+    inline void pushr(Cell value) {
+        if (rsp == rstack + ReturnStackSize - 1)
+            std::longjmp(jmpbuf, static_cast<int>(Error::pushr));
+        *++rsp = value;
+    }
+
+    inline Cell popr() {
+        if (rsp < rstack)
+            std::longjmp(jmpbuf, static_cast<int>(Error::popr));
+        return *rsp--;
+    }
+
+    inline Cell& top() {
+        if (dsp < dstack)
+            std::longjmp(jmpbuf, static_cast<int>(Error::top));
+        return *dsp;
+    }
+
+    inline Cell& pick(std::size_t i) {
+        if (dsp - i < dstack)
+            std::longjmp(jmpbuf, static_cast<int>(Error::pick));
+        return *(dsp - i);
+    }
+};
+
+#endif // ALEEFORTH_STATE_HPP
+
diff --git a/libalee/types.hpp b/libalee/types.hpp
new file mode 100644 (file)
index 0000000..530ff4f
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * Alee Forth: A portable and concise Forth implementation in modern C++.
+ * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALEEFORTH_TYPES_HPP
+#define ALEEFORTH_TYPES_HPP
+
+#include <cstdint>
+
+struct State;
+
+using Addr = uint16_t;
+using Cell = int16_t;
+using DoubleCell = int32_t;
+using Func = void (*)(State&);
+
+constexpr unsigned int MaxCellNumberChars = 6; // -32768
+
+struct Word
+{
+    Addr start = 0;
+    Addr end = 0;
+
+    unsigned size() const noexcept {
+        return end - start;
+    }
+};
+
+#endif // ALEEFORTH_TYPES_HPP
+
index c8ccce0ff703022cd34db308510648a685c0fb59..398af0f06b331c0ae6acaa9b1f6e20a4aebdd727 100644 (file)
@@ -19,7 +19,7 @@
 #ifndef ALEEFORTH_MEMDICT_HPP
 #define ALEEFORTH_MEMDICT_HPP
 
-#include "dictionary.hpp"
+#include "alee.hpp"
 
 #ifndef MEMDICTSIZE
 #define MEMDICTSIZE (65536)
diff --git a/parser.cpp b/parser.cpp
deleted file mode 100644 (file)
index 44b5cec..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * Alee Forth: A portable and concise Forth implementation in modern C++.
- * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "corewords.hpp"
-#include "parser.hpp"
-
-#include <charconv>
-#include <cstring>
-
-int Parser::parse(State& state, const char *str)
-{
-    auto addr = Dictionary::Input;
-    state.dict.write(addr, 0);
-    state.dict.write(Dictionary::SourceLen, std::strlen(str));
-
-    addr += sizeof(Cell);
-    while (*str)
-        state.dict.writebyte(addr++, *str++);
-
-    while (addr < Dictionary::Input + Dictionary::InputCells)
-        state.dict.writebyte(addr++, '\0');
-
-    return parseSource(state);
-}
-
-int Parser::parseSource(State& state)
-{
-    auto word = state.dict.input();
-    while (word.size() > 0) {
-        if (auto ret = parseWord(state, word); ret)
-            return ret;
-
-        word = state.dict.input();
-    }
-
-    return 0;
-}
-
-int Parser::parseWord(State& state, Word word)
-{
-    int ins, imm;
-
-    ins = state.dict.find(word);
-
-    if (ins <= 0) {
-        ins = CoreWords::findi(state, word);
-
-        if (ins < 0)
-            return parseNumber(state, word);
-        else
-            imm = ins == CoreWords::Semicolon;
-    } else {
-        imm = state.dict.read(ins) & CoreWords::Immediate;
-        ins = state.dict.getexec(ins);
-    }
-
-    if (state.compiling() && !imm)
-        state.dict.add(ins);
-    else if (auto stat = state.execute(ins); stat != State::Error::none)
-        return static_cast<int>(stat);
-
-    return 0;
-}
-
-int Parser::parseNumber(State& state, Word word)
-{
-    char buf[MaxCellNumberChars + 1];
-    unsigned i;
-    for (i = 0; i < std::min(MaxCellNumberChars, word.size()); ++i)
-        buf[i] = state.dict.readbyte(word.start + i);
-    buf[i] = '\0';
-
-    auto base = state.dict.read(0);
-    DoubleCell dl;
-    auto [ptr, ec] = std::from_chars(buf, buf + i, dl, base);
-    Cell l = static_cast<Cell>(dl);
-
-    if (ec == std::errc() && ptr == buf + i) {
-        if (state.compiling()) {
-            auto ins = CoreWords::findi("_lit");
-
-            //if (l >= 0 && l < 0xFF) {
-            //    state.dict.add(ins | ((l + 1) << 8));
-            //} else {
-                state.dict.add(ins);
-                state.dict.add(l);
-            //}
-        } else {
-            state.push(l);
-        }
-
-        return 0;
-    } else {
-        return UnknownWord;
-    }
-}
-
diff --git a/parser.hpp b/parser.hpp
deleted file mode 100644 (file)
index 4b14d64..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * Alee Forth: A portable and concise Forth implementation in modern C++.
- * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-#ifndef ALEEFORTH_PARSER_HPP
-#define ALEEFORTH_PARSER_HPP
-
-#include "types.hpp"
-
-#include <string_view>
-
-class Parser
-{
-public:
-    constexpr static int UnknownWord = -1;
-
-    int parse(State&, const char *);
-    int parseSource(State&);
-
-private:
-    int parseWord(State&, Word);
-    int parseNumber(State&, Word);
-};
-
-#endif // ALEEFORTH_PARSER_HPP
-
index 083ce537b2d864525b9905f303b0591cb2410db6..66319472dcd575d1ff7afed3c5f23c0ee7ad5453 100644 (file)
@@ -19,7 +19,7 @@
 #ifndef ALEEFORTH_SPLITMEMDICT_HPP
 #define ALEEFORTH_SPLITMEMDICT_HPP
 
-#include "dictionary.hpp"
+#include "alee.hpp"
 
 #include <cstring>
 
diff --git a/state.cpp b/state.cpp
deleted file mode 100644 (file)
index ea6c601..0000000
--- a/state.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * Alee Forth: A portable and concise Forth implementation in modern C++.
- * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-#include "corewords.hpp"
-#include "state.hpp"
-
-#include <iterator>
-
-bool State::compiling() const
-{
-    return dict.read(Dictionary::Compiling);
-}
-
-void State::compiling(bool yes)
-{
-    dict.write(Dictionary::Compiling, yes);
-}
-
-State::Error State::execute(Addr addr)
-{
-    auto stat = static_cast<State::Error>(setjmp(jmpbuf));
-
-    if (stat == State::Error::none) {
-        CoreWords::run(addr, *this);
-
-        if (ip >= Dictionary::Begin) {
-            // longjmp will exit this loop.
-            for (;;)
-                CoreWords::run(dict.read(ip), *this);
-        } else {
-            // addr was a CoreWord, all done now.
-            ip = 0;
-        }
-    } else if (stat == State::Error::exit) {
-        stat = State::Error::none;
-    }
-
-    return stat;
-}
-
-std::size_t State::size() const noexcept
-{
-    return std::distance(dstack, static_cast<const Cell *>(dsp)) + 1;
-}
-
-std::size_t State::rsize() const noexcept
-{
-    return std::distance(rstack, static_cast<const Cell *>(rsp)) + 1;
-}
-
diff --git a/state.hpp b/state.hpp
deleted file mode 100644 (file)
index 28396dc..0000000
--- a/state.hpp
+++ /dev/null
@@ -1,109 +0,0 @@
-/**
- * Alee Forth: A portable and concise Forth implementation in modern C++.
- * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-#ifndef ALEEFORTH_STATE_HPP
-#define ALEEFORTH_STATE_HPP
-
-#include "dictionary.hpp"
-#include "types.hpp"
-
-#include <csetjmp>
-#include <cstddef>
-
-constexpr unsigned DataStackSize = 16;
-constexpr unsigned ReturnStackSize = 16;
-
-struct State
-{
-    enum class Error : int {
-        none = 0,
-        push,
-        pop,
-        pushr,
-        popr,
-        top,
-        pick,
-        exit
-    };
-
-    Addr ip = 0;
-    Dictionary& dict;
-    void (*input)(State&);
-
-    Cell dstack[DataStackSize] = {};
-    Cell rstack[ReturnStackSize] = {};
-    Cell *dsp = dstack - 1;
-    Cell *rsp = rstack - 1;
-
-    std::jmp_buf jmpbuf = {};
-
-    constexpr State(Dictionary& d, void (*i)(State&)):
-        dict(d), input(i) {}
-
-    bool compiling() const;
-    void compiling(bool);
-
-    Error execute(Addr);
-
-    std::size_t size() const noexcept;
-    std::size_t rsize() const noexcept;
-
-    inline void push(Cell value) {
-        if (dsp == dstack + DataStackSize - 1)
-            std::longjmp(jmpbuf, static_cast<int>(Error::push));
-        *++dsp = value;
-    }
-
-    inline Cell pop() {
-        if (dsp < dstack)
-            std::longjmp(jmpbuf, static_cast<int>(Error::pop));
-        return *dsp--;
-    }
-
-    inline Cell beyondip() {
-        ip += sizeof(Cell);
-        return dict.read(ip);
-    }
-
-    inline void pushr(Cell value) {
-        if (rsp == rstack + ReturnStackSize - 1)
-            std::longjmp(jmpbuf, static_cast<int>(Error::pushr));
-        *++rsp = value;
-    }
-
-    inline Cell popr() {
-        if (rsp < rstack)
-            std::longjmp(jmpbuf, static_cast<int>(Error::popr));
-        return *rsp--;
-    }
-
-    inline Cell& top() {
-        if (dsp < dstack)
-            std::longjmp(jmpbuf, static_cast<int>(Error::top));
-        return *dsp;
-    }
-
-    inline Cell& pick(std::size_t i) {
-        if (dsp - i < dstack)
-            std::longjmp(jmpbuf, static_cast<int>(Error::pick));
-        return *(dsp - i);
-    }
-};
-
-#endif // ALEEFORTH_STATE_HPP
-
diff --git a/types.hpp b/types.hpp
deleted file mode 100644 (file)
index 530ff4f..0000000
--- a/types.hpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * Alee Forth: A portable and concise Forth implementation in modern C++.
- * Copyright (C) 2023  Clyne Sullivan <clyne@bitgloo.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-#ifndef ALEEFORTH_TYPES_HPP
-#define ALEEFORTH_TYPES_HPP
-
-#include <cstdint>
-
-struct State;
-
-using Addr = uint16_t;
-using Cell = int16_t;
-using DoubleCell = int32_t;
-using Func = void (*)(State&);
-
-constexpr unsigned int MaxCellNumberChars = 6; // -32768
-
-struct Word
-{
-    Addr start = 0;
-    Addr end = 0;
-
-    unsigned size() const noexcept {
-        return end - start;
-    }
-};
-
-#endif // ALEEFORTH_TYPES_HPP
-