]> code.bitgloo.com Git - bitgloo/alee-forth.git/commitdiff
build core.fth into executable
authorClyne Sullivan <clyne@bitgloo.com>
Wed, 8 Mar 2023 18:41:02 +0000 (13:41 -0500)
committerClyne Sullivan <clyne@bitgloo.com>
Wed, 8 Mar 2023 18:41:02 +0000 (13:41 -0500)
.gitignore
Makefile
alee-standalone.cpp [new file with mode: 0644]
splitmemdict.hpp [new file with mode: 0644]

index a877dd4c3b4ea2231f49e1340de6fb75b869e87c..0c8292521fe08476c457327d352104dc7d2c1975 100644 (file)
@@ -1,5 +1,8 @@
 .*
 *.o
+*.dat
 alee
 alee-msp430
+alee-standalone
 libalee.a
+core.fth.h
index 66d9132c45d4f7006492ce777e9fffe3f0169f76..60b4922959fef6911d146fb9525f3e4be8c2bbfa 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,8 @@ all: alee
 
 msp430: CXX := msp430-elf32-g++
 msp430: AR := msp430-elf32-ar
-msp430: CXXFLAGS += -Os -mmcu=msp430g2553 -ffunction-sections -fdata-sections -DMEMDICTSIZE=200
+msp430: CXXFLAGS += -Os -mmcu=msp430g2553 -ffunction-sections -fdata-sections
+msp430: CXXFLAGS += -DMEMDICTSIZE=200
 msp430: LDFLAGS += -L/opt/msp430-elf32/include -Wl,-gc-sections
 msp430: alee-msp430
 
@@ -20,13 +21,25 @@ small: alee
 fast: CXXFLAGS += -O3 -march=native -mtune=native -flto
 fast: alee
 
-alee: $(LIBFILE)
+standalone: core.fth.h alee-standalone
 
+alee: $(LIBFILE)
 alee-msp430: $(LIBFILE)
+alee-standalone: $(LIBFILE)
 
 $(LIBFILE): $(OBJFILES)
        $(AR) cr $@ $(OBJFILES)
 
+core.fth.h: alee.dat
+       xxd -i $< > $@
+       sed -i "s/unsigned /static const &/" $@
+
+alee.dat: alee core.fth
+       echo "2 sys" | ./alee core.fth
+
 clean:
-       rm -f alee alee-msp430 $(LIBFILE) $(OBJFILES)
+       rm -f alee alee-msp430 alee-standalone
+       rm -f $(LIBFILE) $(OBJFILES) alee.dat core.fth.h
+
+.PHONY: all msp430 small fast standalone clean
 
diff --git a/alee-standalone.cpp b/alee-standalone.cpp
new file mode 100644 (file)
index 0000000..1602641
--- /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 "alee.hpp"
+#include "splitmemdict.hpp"
+
+#include <charconv>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include "core.fth.h"
+
+static bool okay = false;
+
+static void readchar(State& state);
+static void parseLine(Parser&, State&, const std::string&);
+static void parseFile(Parser&, State&, std::istream&);
+
+static Parser parser;
+
+int main(int argc, char *argv[])
+{
+    SplitMemDict<alee_dat_len> dict (alee_dat);
+    State state (dict, readchar);
+
+    std::vector args (argv + 1, argv + argc);
+    for (const auto& a : args) {
+        std::ifstream file (a);
+        parseFile(parser, state, file);
+    }
+
+    okay = true;
+    parseFile(parser, state, std::cin);
+
+    return 0;
+}
+
+static void readchar(State& state)
+{
+    auto idx = state.dict.read(Dictionary::Input);
+    Addr addr = Dictionary::Input + sizeof(Cell) + idx;
+
+    auto c = std::cin.get();
+    if (isupper(c))
+        c += 32;
+    state.dict.writebyte(addr, c ? c : ' ');
+}
+
+static void save(State& state)
+{
+    std::ofstream file ("alee.dat", std::ios::binary);
+
+    if (file.good()) {
+        for (Addr i = 0; i < state.dict.here(); ++i)
+            file.put(state.dict.readbyte(i));
+    }
+}
+
+static void load(State& state)
+{
+    std::ifstream file ("alee.dat", std::ios::binary);
+
+    Addr i = 0;
+    while (file.good())
+        state.dict.writebyte(i++, file.get());
+}
+
+#include <cstring>
+void user_sys(State& state)
+{
+    char buf[32] = {0};
+
+    switch (state.pop()) {
+    case 0: // .
+        std::to_chars(buf, buf + sizeof(buf), state.pop(),
+                      state.dict.read(Dictionary::Base));
+        std::cout << buf << ' ';
+        break;
+    case 1: // emit
+        std::cout << static_cast<char>(state.pop());
+        break;
+    case 2: // save
+        save(state);
+        break;
+    case 3: // load
+        load(state);
+        break;
+    case 4: // u.
+        {
+        Addr ucell = static_cast<Addr>(state.pop());
+        std::to_chars(buf, buf + sizeof(buf), ucell,
+                      state.dict.read(Dictionary::Base));
+        std::cout << buf << ' ';
+        }
+        break;
+    case 5: // eval
+        {
+        auto oldip = state.ip;
+        std::jmp_buf oldjb;
+        memcpy(oldjb, state.jmpbuf, sizeof(std::jmp_buf));
+        state.ip = 0;
+        parser.parseSource(state);
+        memcpy(state.jmpbuf, oldjb, sizeof(std::jmp_buf));
+        state.ip = oldip;
+        }
+        break;
+    }
+}
+
+void parseLine(Parser& parser, State& state, const std::string& line)
+{
+    if (auto r = parser.parse(state, line.c_str()); r == 0) {
+        if (okay)
+            std::cout << (state.compiling() ? "compiled" : "ok") << std::endl;
+    } else {
+        switch (r) {
+        case Parser::UnknownWord:
+            std::cout << "word not found in: " << line << std::endl;
+            break;
+        case static_cast<int>(State::Error::push):
+            std::cout << "stack overflow" << std::endl;
+            break;
+        case static_cast<int>(State::Error::pushr):
+            std::cout << "return stack overflow" << std::endl;
+            break;
+        case static_cast<int>(State::Error::popr):
+            std::cout << "return stack underflow" << std::endl;
+            break;
+        case static_cast<int>(State::Error::pop):
+        case static_cast<int>(State::Error::top):
+        case static_cast<int>(State::Error::pick):
+            std::cout << "stack underflow" << std::endl;
+            break;
+        default:
+            std::cout << "error: " << r << std::endl;
+            break;
+        }
+
+        while (state.size())
+            state.pop();
+        while (state.rsize())
+            state.popr();
+        state.dict.write(Dictionary::Compiling, 0);
+        state.ip = 0;
+    }
+}
+
+void parseFile(Parser& parser, State& state, std::istream& file)
+{
+    while (file.good()) {
+        std::string line;
+        std::getline(file, line);
+
+        if (line == "bye")
+            exit(0);
+
+        parseLine(parser, state, line);
+    }
+}
+
diff --git a/splitmemdict.hpp b/splitmemdict.hpp
new file mode 100644 (file)
index 0000000..083ce53
--- /dev/null
@@ -0,0 +1,85 @@
+/**
+ * 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_SPLITMEMDICT_HPP
+#define ALEEFORTH_SPLITMEMDICT_HPP
+
+#include "dictionary.hpp"
+
+#include <cstring>
+
+#ifndef MEMDICTSIZE
+#define MEMDICTSIZE (65536)
+#endif
+constexpr unsigned long int MemDictSize = MEMDICTSIZE;
+
+template<unsigned long int RON>
+class SplitMemDict : public Dictionary
+{
+    const uint8_t *rodict;
+    uint8_t rwdict[MemDictSize];
+    uint8_t extra[Dictionary::Begin];
+
+public:
+    constexpr SplitMemDict(const uint8_t *rod):
+        rodict(rod)
+    {
+        std::memcpy(extra, rodict, sizeof(extra));
+    }
+
+    virtual Cell read(Addr addr) const noexcept final {
+        const uint8_t *dict;
+        if (addr < RON) {
+            dict = addr < Dictionary::Begin ? extra : rodict;
+        } else {
+            dict = rwdict;
+            addr -= RON;
+        }
+
+        return *reinterpret_cast<const Cell *>(dict + addr);
+    }
+
+    virtual void write(Addr addr, Cell value) noexcept final {
+        if (addr >= RON)
+            *reinterpret_cast<Cell *>(rwdict + addr - RON) = value;
+        else if (addr < Dictionary::Begin)
+            *reinterpret_cast<Cell *>(extra + addr) = value;
+    }
+
+    virtual uint8_t readbyte(Addr addr) const noexcept final {
+        const uint8_t *dict;
+        if (addr < RON) {
+            dict = addr < Dictionary::Begin ? extra : rodict;
+        } else {
+            dict = rwdict;
+            addr -= RON;
+        }
+
+        return dict[addr];
+    }
+
+    virtual void writebyte(Addr addr, uint8_t value) noexcept final {
+        if (addr >= RON)
+            rwdict[addr - RON] = value;
+        else if (addr < Dictionary::Begin)
+            extra[addr] = value;
+    }
+};
+
+#endif // ALEEFORTH_SPLITMEMDICT_HPP
+