]> code.bitgloo.com Git - bitgloo/alee-forth.git/commitdiff
build as library; add small target
authorClyne Sullivan <clyne@bitgloo.com>
Thu, 9 Feb 2023 21:41:34 +0000 (16:41 -0500)
committerClyne Sullivan <clyne@bitgloo.com>
Thu, 9 Feb 2023 21:41:34 +0000 (16:41 -0500)
14 files changed:
.gitignore
Makefile
alee.cpp
alee.hpp [new file with mode: 0644]
corewords.hpp
dictionary.cpp [new file with mode: 0644]
dictionary.hpp
executor.cpp [new file with mode: 0644]
executor.hpp
parser.cpp [new file with mode: 0644]
parser.hpp
state.cpp [new file with mode: 0644]
state.hpp
types.hpp

index fa983e16c246e1822c3d8fdb13cd756b2a35f413..fb13a21dbd05ca7a632c9422ffaa729505f41902 100644 (file)
@@ -1,3 +1,4 @@
 .*
 *.o
 alee
+libalee.a
index b34026a80c1d7b2c3da2d6acd90748a33448f420..36e299d01b24264cbff0982a7a2630a26daf89c7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,21 @@
-CXXFLAGS += -g3 -ggdb -O0
+CXXFLAGS += -std=c++17 -g3 -ggdb -O0
 
-CXXFILES := corewords.cpp types.cpp
+CXXFILES := corewords.cpp dictionary.cpp executor.cpp parser.cpp state.cpp \
+           types.cpp
 OBJFILES := $(subst .cpp,.o,$(CXXFILES))
+LIBFILE := libalee.a
 EXEFILE := alee
 
-all: alee
+all: $(EXEFILE)
 
-alee: $(OBJFILES)
+small: CXXFLAGS += -Os
+small: $(EXEFILE)
+
+$(EXEFILE): $(LIBFILE)
+
+$(LIBFILE): $(OBJFILES)
+       $(AR) cr $@ $(OBJFILES)
 
 clean:
-       rm -f alee $(OBJFILES)
+       rm -f $(EXEFILE) $(LIBFILE) $(OBJFILES)
 
index b7858e67e1d0cd42b0f57d2c646b53ca25a60f87..1232aa6173d6bd0e6d23b7df060b4078f8c53edc 100644 (file)
--- a/alee.cpp
+++ b/alee.cpp
@@ -16,8 +16,8 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
+#include "alee.hpp"
 #include "memdict.hpp"
-#include "parser.hpp"
 
 #include <fstream>
 #include <iostream>
diff --git a/alee.hpp b/alee.hpp
new file mode 100644 (file)
index 0000000..f091cf8
--- /dev/null
+++ b/alee.hpp
@@ -0,0 +1,3 @@
+#include "parser.hpp"
+#include "state.hpp"
+
index ff9d84dd2200c74dc7a41852227ac4a5f8ce6452..54e02f19d2708ddd9e5115120d1a3b419bc5b9ef 100644 (file)
@@ -34,9 +34,9 @@ public:
 
     constexpr static Cell Immediate = (1 << 5);
 
-    static int findi(std::string_view str);
-    static Func find(std::string_view str);
-    static void run(int i, State& state);
+    static int findi(std::string_view);
+    static Func find(std::string_view);
+    static void run(int, State&);
 
 private:
     constexpr static char wordsarr[] =
@@ -48,40 +48,40 @@ private:
         ";\0here\0exit\0imm\0const\0";
     // lit, jmp, jmp0, ', lits
 
-    static Func get(int index);
+    static Func get(int);
 
-    static int op_drop(State& state);
-    static int op_dup(State& state);
-    static int op_swap(State& state);
-    static int op_pick(State& state);
-    static int op_sys(State& state);
-    static int op_add(State& state);
-    static int op_sub(State& state);
-    static int op_mul(State& state);
-    static int op_div(State& state);
-    static int op_mod(State& state);
-    static int op_peek(State& state);
-    static int op_poke(State& state);
-    static int op_rot(State& state);
-    static int op_pushr(State& state);
-    static int op_popr(State& state);
-    static int op_eq(State& state);
-    static int op_lt(State& state);
-    static int op_allot(State& state);
-    static int op_and(State& state);
-    static int op_or(State& state);
-    static int op_xor(State& state);
-    static int op_shl(State& state);
-    static int op_shr(State& state);
-    static int op_comment(State& state);
-    static int op_colon(State& state);
-    static int op_semic(State& state);
-    static int op_here(State& state);
-    static int op_exit(State& state);
-    static int op_imm(State& state);
-    static int op_const(State& state);
-    static int op_literal(State& state);
-    static int op_jump(State& state);
+    static int op_drop(State&);
+    static int op_dup(State&);
+    static int op_swap(State&);
+    static int op_pick(State&);
+    static int op_sys(State&);
+    static int op_add(State&);
+    static int op_sub(State&);
+    static int op_mul(State&);
+    static int op_div(State&);
+    static int op_mod(State&);
+    static int op_peek(State&);
+    static int op_poke(State&);
+    static int op_rot(State&);
+    static int op_pushr(State&);
+    static int op_popr(State&);
+    static int op_eq(State&);
+    static int op_lt(State&);
+    static int op_allot(State&);
+    static int op_and(State&);
+    static int op_or(State&);
+    static int op_xor(State&);
+    static int op_shl(State&);
+    static int op_shr(State&);
+    static int op_comment(State&);
+    static int op_colon(State&);
+    static int op_semic(State&);
+    static int op_here(State&);
+    static int op_exit(State&);
+    static int op_imm(State&);
+    static int op_const(State&);
+    static int op_literal(State&);
+    static int op_jump(State&);
 };
 
 #endif // ALEEFORTH_COREWORDS_HPP
diff --git a/dictionary.cpp b/dictionary.cpp
new file mode 100644 (file)
index 0000000..dced709
--- /dev/null
@@ -0,0 +1,80 @@
+/**
+ * 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"
+
+Addr Dictionary::allot(Cell amount)
+{
+    Addr old = here;
+    here += amount;
+    return old;
+}
+
+void Dictionary::add(Cell value)
+{
+    write(here++, value);
+}
+
+void Dictionary::addDefinition(std::string_view str)
+{
+    add(str.size());
+    for (char c : str)
+        add(c);
+
+    if (here & 1)
+        allot(1);
+}
+
+bool Dictionary::issame(Addr addr, std::string_view str, std::size_t n)
+{
+    if (str.size() != n)
+        return false;
+
+    for (char c : str) {
+        if (read(addr++) != c)
+            return false;
+    }
+
+    return true;
+}
+
+Addr Dictionary::find(std::string_view str)
+{
+    if (latest == 0)
+        return 0;
+
+    auto lt = latest;
+    do {
+        const auto l = read(lt);
+        const auto len = l & 0x1F;
+
+        if (issame(lt + 1, str, len))
+            return lt;
+        else
+            lt -= l >> 6;
+    } while (lt);
+
+    return 0;
+}
+
+Addr Dictionary::getexec(Addr addr)
+{
+    const auto len = read(addr) & 0x1F;
+    return ((addr + 1 + len) + 1) & ~1;
+}
+
index 880b8a50c7eff64429691910f15c7136117e94a6..add7fc3c8c5646f39b89b818ce302dcd3011efbb 100644 (file)
 #include <cstddef>
 #include <string_view>
 
-struct Dictionary
+class Dictionary
 {
+public:
     Addr here = 1;
     Addr latest = 0;
 
     virtual Cell read(Addr) const = 0;
     virtual int write(Addr, Cell) = 0;
 
-    Addr allot(Cell amount) {
-        Addr old = here;
-        here += amount;
-        return old;
-    }
+    Addr allot(Cell);
+    void add(Cell);
+    void addDefinition(std::string_view);
+    Addr find(std::string_view);
+    Addr getexec(Addr);
 
-    void add(Cell value) {
-        write(here++, value);
-    }
-
-    void addDefinition(std::string_view str) {
-        add(str.size());
-        for (char c : str)
-            add(c);
-
-        if (here & 1)
-            allot(1);
-    }
-
-    bool issame(Addr addr, std::string_view str, std::size_t n) {
-        if (str.size() != n)
-            return false;
-
-        for (char c : str) {
-            if (read(addr++) != c)
-                return false;
-        }
-    
-        return true;
-    }
-
-    Addr find(std::string_view str) {
-        if (latest == 0)
-            return 0;
-
-        auto lt = latest;
-        do {
-            const auto l = read(lt);
-            const auto len = l & 0x1F;
-
-            if (issame(lt + 1, str, len))
-                return lt;
-            else
-                lt -= l >> 6;
-        } while (lt);
-
-        return 0;
-    }
-
-    Addr getexec(Addr addr) {
-        const auto len = read(addr) & 0x1F;
-        return ((addr + 1 + len) + 1) & ~1;
-    }
+private:
+    bool issame(Addr, std::string_view, std::size_t);
 };
 
 #endif // ALEEFORTH_DICTIONARY_HPP
diff --git a/executor.cpp b/executor.cpp
new file mode 100644 (file)
index 0000000..30d43fc
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * 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 "executor.hpp"
+
+int Executor::fullexec(State& state, Addr addr)
+{
+    state.pushr(0);
+    state.ip = addr - 1;
+
+    do {
+        ++state.ip;
+        CoreWords::run(state.dict.read(state.ip), state);
+    } while (state.ip);
+    
+    return 0;
+}
+
index 62afe5fc8afa8d7eb8b33c396a3ec664433985ee..66c675b3752e1ccdf1387fc620bf42b2591e3236 100644 (file)
 #ifndef ALEEFORTH_EXECUTOR_HPP
 #define ALEEFORTH_EXECUTOR_HPP
 
-#include "corewords.hpp"
+#include "types.hpp"
 
 class Executor
 {
 public:
-    static int fullexec(State& state, Addr addr) {
-        state.pushr(0);
-        state.ip = addr - 1;
-
-        do {
-            ++state.ip;
-            CoreWords::run(state.dict.read(state.ip), state);
-        } while (state.ip);
-        
-        return 0;
-    }
+    static int fullexec(State&, Addr);
 };
 
 #endif // ALEEFORTH_EXECUTOR_HPP
diff --git a/parser.cpp b/parser.cpp
new file mode 100644 (file)
index 0000000..d57365b
--- /dev/null
@@ -0,0 +1,107 @@
+/**
+ * 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 "executor.hpp"
+#include "parser.hpp"
+
+#include <cstdlib>
+
+ParseStatus Parser::parse(State& state, std::string_view& str)
+{
+    const auto end = str.find_first_of(" \t\n\r");
+    const auto sub = str.substr(0, end);
+    if (sub.empty())
+        return ParseStatus::Finished;
+
+    if (state.pass != Pass::None) {
+        switch (state.pass) {
+        case Pass::Comment:
+            if (str.front() == ')')
+                state.pass = Pass::None;
+
+            str = str.substr(1);
+            break;
+        case Pass::Colon:
+            state.pass = Pass::None;
+                state.compiling = true;
+            state.dict.addDefinition(sub);
+            break;
+        case Pass::Constant:
+            state.pass = Pass::None;
+            state.compiling = true;
+            state.dict.addDefinition(sub);
+            state.dict.add(CoreWords::HiddenWordLiteral);
+            state.dict.add(state.pop());
+            state.dict.add(CoreWords::findi(";"));
+            CoreWords::run(CoreWords::findi(";"), state);
+            break;
+        default:
+            break;
+        }
+    } else {
+        if (auto i = CoreWords::findi(sub); i >= 0) {
+            if (state.compiling)
+                state.dict.add(i);
+            if (!state.compiling || sub.front() == ';')
+                CoreWords::run(i, state);
+        } else if (auto j = state.dict.find(sub); j > 0) {
+            auto e = state.dict.getexec(j);
+
+            if (state.compiling) {
+                if (state.dict.read(j) & CoreWords::Immediate) {
+                    state.compiling = false;
+                    Executor::fullexec(state, e);
+                    state.compiling = true;
+                } else {
+                    state.dict.add(CoreWords::HiddenWordJump);
+                    state.dict.add(e);
+                }
+            } else {
+                Executor::fullexec(state, e);
+            }
+        } else {
+            char *p;
+            const auto l = static_cast<Cell>(std::strtol(sub.data(), &p, 10));
+
+            if (p != sub.data()) {
+                if (state.compiling) {
+                    state.dict.add(CoreWords::HiddenWordLiteral);
+                    state.dict.add(l);
+                } else {
+                    state.push(l);
+                }
+            } else {
+                return ParseStatus::Error;
+            }
+        }
+
+        if (end == std::string_view::npos)
+            return ParseStatus::Finished;
+    }
+
+    const auto next = str.find_first_not_of(" \t\n\r", end);
+
+    if (next == std::string_view::npos) {
+        return ParseStatus::Finished;
+    } else {
+        str = str.substr(next);
+        return ParseStatus::Continue;
+    }
+}
+
index c136990ee7a5ea66e0da1b50c9601fb01a3757c0..b45a5d0b07f7b063ba0182620cf27b5a29562701 100644 (file)
 #ifndef ALEEFORTH_PARSER_HPP
 #define ALEEFORTH_PARSER_HPP
 
-#include "executor.hpp"
+#include "types.hpp"
+
+#include <string_view>
 
 class Parser
 {
 public:
-    ParseStatus parse(State& state, std::string_view& str) {
-        const auto end = str.find_first_of(" \t\n\r");
-        const auto sub = str.substr(0, end);
-        if (sub.empty())
-            return ParseStatus::Finished;
-
-        if (state.pass != Pass::None) {
-            switch (state.pass) {
-            case Pass::Comment:
-                if (str.front() == ')')
-                    state.pass = Pass::None;
-
-                str = str.substr(1);
-                break;
-            case Pass::Colon:
-                state.pass = Pass::None;
-                    state.compiling = true;
-                state.dict.addDefinition(sub);
-                break;
-            case Pass::Constant:
-                state.pass = Pass::None;
-                state.compiling = true;
-                state.dict.addDefinition(sub);
-                state.dict.add(CoreWords::HiddenWordLiteral);
-                state.dict.add(state.pop());
-                state.dict.add(CoreWords::findi(";"));
-                CoreWords::run(CoreWords::findi(";"), state);
-                break;
-            default:
-                break;
-            }
-        } else {
-            if (auto i = CoreWords::findi(sub); i >= 0) {
-                if (state.compiling)
-                    state.dict.add(i);
-                if (!state.compiling || sub.front() == ';')
-                    CoreWords::run(i, state);
-            } else if (auto j = state.dict.find(sub); j > 0) {
-                auto e = state.dict.getexec(j);
-
-                if (state.compiling) {
-                    if (state.dict.read(j) & CoreWords::Immediate) {
-                        state.compiling = false;
-                        Executor::fullexec(state, e);
-                        state.compiling = true;
-                    } else {
-                        state.dict.add(CoreWords::HiddenWordJump);
-                        state.dict.add(e);
-                    }
-                } else {
-                    Executor::fullexec(state, e);
-                }
-            } else {
-                char *p;
-                const auto l = static_cast<Cell>(std::strtol(sub.data(), &p, 10));
-
-                if (p != sub.data()) {
-                    if (state.compiling) {
-                        state.dict.add(CoreWords::HiddenWordLiteral);
-                        state.dict.add(l);
-                    } else {
-                        state.push(l);
-                    }
-                } else {
-                    return ParseStatus::Error;
-                }
-            }
-
-            if (end == std::string_view::npos)
-                return ParseStatus::Finished;
-        }
-
-        const auto next = str.find_first_not_of(" \t\n\r", end);
-
-        if (next == std::string_view::npos) {
-            return ParseStatus::Finished;
-        } else {
-            str = str.substr(next);
-            return ParseStatus::Continue;
-        }
-    }
+    ParseStatus parse(State&, std::string_view&);
 };
 
 #endif // ALEEFORTH_PARSER_HPP
diff --git a/state.cpp b/state.cpp
new file mode 100644 (file)
index 0000000..0b5c8fe
--- /dev/null
+++ b/state.cpp
@@ -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/>.
+ */
+
+#include "state.hpp"
+
+#include <iterator>
+
+Cell State::beyondip() const
+{
+    return dict.read(ip + 1);
+}
+
+void State::pushr(Cell value)
+{
+    if (rsize() == ReturnStackSize)
+        throw;
+    *++rsp = value;
+}
+
+Cell State::popr()
+{
+    if (rsize() == 0)
+        throw;
+    return *rsp--;
+}
+
+void State::push(Cell value)
+{
+    if (size() == DataStackSize)
+        throw;
+    *++dsp = value;
+}
+
+Cell State::pop()
+{
+    if (size() == 0)
+        throw;
+    return *dsp--;
+}
+
+Cell& State::top()
+{
+    if (size() == 0)
+        throw;
+    return *dsp;
+}
+
+Cell& State::pick(std::size_t i)
+{
+    if (i >= size())
+        throw;
+    return *(dsp - i);
+}
+
+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;
+}
+
index e1788773b8377a0b93a144cddacd08551a1ce9e6..63119493d78b017181a019a18a31514058f7f98e 100644 (file)
--- a/state.hpp
+++ b/state.hpp
@@ -23,7 +23,6 @@
 #include "types.hpp"
 
 #include <cstddef>
-#include <iterator>
 
 constexpr unsigned DataStackSize = 12;
 constexpr unsigned ReturnStackSize = 12;
@@ -43,53 +42,19 @@ public:
 
     constexpr State(Dictionary& d): dict(d) {}
 
-    Cell beyondip() const {
-        return dict.read(ip + 1);
-    }
+    Cell beyondip() const;
 
-    void pushr(Cell value) {
-        if (rsize() == ReturnStackSize)
-            throw;
-        *++rsp = value;
-    }
+    void pushr(Cell);
+    Cell popr();
 
-    Cell popr() {
-        if (rsize() == 0)
-            throw;
-        return *rsp--;
-    }
+    void push(Cell);
+    Cell pop();
 
-    void push(Cell value) {
-        if (size() == DataStackSize)
-            throw;
-        *++dsp = value;
-    }
+    Cell& top();
+    Cell& pick(std::size_t);
 
-    Cell pop() {
-        if (size() == 0)
-            throw;
-        return *dsp--;
-    }
-
-    Cell& top() {
-        if (size() == 0)
-            throw;
-        return *dsp;
-    }
-
-    Cell& pick(std::size_t i) {
-        if (i >= size())
-            throw;
-        return *(dsp - i);
-    }
-
-    std::size_t size() const noexcept {
-        return std::distance(dstack, static_cast<const Cell *>(dsp)) + 1;
-    }
-
-    std::size_t rsize() const noexcept {
-        return std::distance(rstack, static_cast<const Cell *>(rsp)) + 1;
-    }
+    std::size_t size() const noexcept;
+    std::size_t rsize() const noexcept;
 };
 
 #endif // ALEEFORTH_STATE_HPP
index 124f5ba029e731a11f4d19da8e1f3bb996633e73..95f9ff100777b8787807bf170035822817f6a8a4 100644 (file)
--- a/types.hpp
+++ b/types.hpp
@@ -43,7 +43,7 @@ enum class ParseStatus
     Error
 };
 
-std::string_view to_string(ParseStatus ps);
+std::string_view to_string(ParseStatus);
 
 #endif // ALEEFORTH_TYPES_HPP