aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClyne Sullivan <clyne@bitgloo.com>2023-03-08 13:41:02 -0500
committerClyne Sullivan <clyne@bitgloo.com>2023-03-08 13:41:02 -0500
commit685accbcba29ccd93d4bf398b0e39a8ec3f25c9a (patch)
tree17634195e68d5e9f1860aa690d7b63d581ae4e7f
parenta529c1591826c120703afd7b88b245f7f659214c (diff)
build core.fth into executable
-rw-r--r--.gitignore3
-rw-r--r--Makefile19
-rw-r--r--alee-standalone.cpp176
-rw-r--r--splitmemdict.hpp85
4 files changed, 280 insertions, 3 deletions
diff --git a/.gitignore b/.gitignore
index a877dd4..0c82925 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,8 @@
.*
*.o
+*.dat
alee
alee-msp430
+alee-standalone
libalee.a
+core.fth.h
diff --git a/Makefile b/Makefile
index 66d9132..60b4922 100644
--- 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
index 0000000..1602641
--- /dev/null
+++ b/alee-standalone.cpp
@@ -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
index 0000000..083ce53
--- /dev/null
+++ b/splitmemdict.hpp
@@ -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
+