From dcd5e792b1d84afd1bea9780781674b6e6ad8dc3 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Wed, 8 Mar 2023 19:57:26 -0500 Subject: move libalee into folder --- Makefile | 4 +- alee.hpp | 4 +- corewords.cpp | 253 ------------------------------------------------- corewords.hpp | 52 ---------- dictionary.cpp | 176 ---------------------------------- dictionary.hpp | 79 --------------- libalee/corewords.cpp | 253 +++++++++++++++++++++++++++++++++++++++++++++++++ libalee/corewords.hpp | 52 ++++++++++ libalee/dictionary.cpp | 176 ++++++++++++++++++++++++++++++++++ libalee/dictionary.hpp | 79 +++++++++++++++ libalee/parser.cpp | 112 ++++++++++++++++++++++ libalee/parser.hpp | 40 ++++++++ libalee/state.cpp | 65 +++++++++++++ libalee/state.hpp | 109 +++++++++++++++++++++ libalee/types.hpp | 44 +++++++++ memdict.hpp | 2 +- parser.cpp | 112 ---------------------- parser.hpp | 40 -------- splitmemdict.hpp | 2 +- state.cpp | 65 ------------- state.hpp | 109 --------------------- types.hpp | 44 --------- 22 files changed, 936 insertions(+), 936 deletions(-) delete mode 100644 corewords.cpp delete mode 100644 corewords.hpp delete mode 100644 dictionary.cpp delete mode 100644 dictionary.hpp create mode 100644 libalee/corewords.cpp create mode 100644 libalee/corewords.hpp create mode 100644 libalee/dictionary.cpp create mode 100644 libalee/dictionary.hpp create mode 100644 libalee/parser.cpp create mode 100644 libalee/parser.hpp create mode 100644 libalee/state.cpp create mode 100644 libalee/state.hpp create mode 100644 libalee/types.hpp delete mode 100644 parser.cpp delete mode 100644 parser.hpp delete mode 100644 state.cpp delete mode 100644 state.hpp delete mode 100644 types.hpp diff --git a/Makefile b/Makefile index 86df6a6..5e75d76 100644 --- 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 diff --git a/alee.hpp b/alee.hpp index f091cf8..87991bb 100644 --- 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 index 4de9413..0000000 --- a/corewords.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/** - * Alee Forth: A portable and concise Forth implementation in modern C++. - * Copyright (C) 2023 Clyne Sullivan - * - * 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 . - */ - -#include "corewords.hpp" - -#include -#include - -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(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(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(state.top()) <<= static_cast(cell); - break; - case 21: // shr - cell = state.pop(); - reinterpret_cast(state.top()) >>= static_cast(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(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 index 21a0951..0000000 --- a/corewords.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Alee Forth: A portable and concise Forth implementation in modern C++. - * Copyright (C) 2023 Clyne Sullivan - * - * 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 . - */ - -#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 index 48230c4..0000000 --- a/dictionary.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/** - * Alee Forth: A portable and concise Forth implementation in modern C++. - * Copyright (C) 2023 Clyne Sullivan - * - * 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 . - */ - -#include "dictionary.hpp" - -#include -#include - -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(read(lt)); - const Addr len = l & 0x1F; - const Word lw { - static_cast(lt + sizeof(Cell)), - static_cast(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 index 4dcae77..0000000 --- a/dictionary.hpp +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Alee Forth: A portable and concise Forth implementation in modern C++. - * Copyright (C) 2023 Clyne Sullivan - * - * 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 . - */ - -#ifndef ALEEFORTH_DICTIONARY_HPP -#define ALEEFORTH_DICTIONARY_HPP - -#include "types.hpp" - -#include -#include - -/** - * 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 index 0000000..4de9413 --- /dev/null +++ b/libalee/corewords.cpp @@ -0,0 +1,253 @@ +/** + * Alee Forth: A portable and concise Forth implementation in modern C++. + * Copyright (C) 2023 Clyne Sullivan + * + * 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 . + */ + +#include "corewords.hpp" + +#include +#include + +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(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(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(state.top()) <<= static_cast(cell); + break; + case 21: // shr + cell = state.pop(); + reinterpret_cast(state.top()) >>= static_cast(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(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 index 0000000..21a0951 --- /dev/null +++ b/libalee/corewords.hpp @@ -0,0 +1,52 @@ +/** + * Alee Forth: A portable and concise Forth implementation in modern C++. + * Copyright (C) 2023 Clyne Sullivan + * + * 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 . + */ + +#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 index 0000000..48230c4 --- /dev/null +++ b/libalee/dictionary.cpp @@ -0,0 +1,176 @@ +/** + * Alee Forth: A portable and concise Forth implementation in modern C++. + * Copyright (C) 2023 Clyne Sullivan + * + * 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 . + */ + +#include "dictionary.hpp" + +#include +#include + +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(read(lt)); + const Addr len = l & 0x1F; + const Word lw { + static_cast(lt + sizeof(Cell)), + static_cast(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 index 0000000..4dcae77 --- /dev/null +++ b/libalee/dictionary.hpp @@ -0,0 +1,79 @@ +/** + * Alee Forth: A portable and concise Forth implementation in modern C++. + * Copyright (C) 2023 Clyne Sullivan + * + * 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 . + */ + +#ifndef ALEEFORTH_DICTIONARY_HPP +#define ALEEFORTH_DICTIONARY_HPP + +#include "types.hpp" + +#include +#include + +/** + * 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 index 0000000..44b5cec --- /dev/null +++ b/libalee/parser.cpp @@ -0,0 +1,112 @@ +/** + * Alee Forth: A portable and concise Forth implementation in modern C++. + * Copyright (C) 2023 Clyne Sullivan + * + * 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 . + */ + +#include "corewords.hpp" +#include "parser.hpp" + +#include +#include + +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(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(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 index 0000000..4b14d64 --- /dev/null +++ b/libalee/parser.hpp @@ -0,0 +1,40 @@ +/** + * Alee Forth: A portable and concise Forth implementation in modern C++. + * Copyright (C) 2023 Clyne Sullivan + * + * 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 . + */ + +#ifndef ALEEFORTH_PARSER_HPP +#define ALEEFORTH_PARSER_HPP + +#include "types.hpp" + +#include + +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 index 0000000..ea6c601 --- /dev/null +++ b/libalee/state.cpp @@ -0,0 +1,65 @@ +/** + * Alee Forth: A portable and concise Forth implementation in modern C++. + * Copyright (C) 2023 Clyne Sullivan + * + * 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 . + */ + +#include "corewords.hpp" +#include "state.hpp" + +#include + +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(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(dsp)) + 1; +} + +std::size_t State::rsize() const noexcept +{ + return std::distance(rstack, static_cast(rsp)) + 1; +} + diff --git a/libalee/state.hpp b/libalee/state.hpp new file mode 100644 index 0000000..28396dc --- /dev/null +++ b/libalee/state.hpp @@ -0,0 +1,109 @@ +/** + * Alee Forth: A portable and concise Forth implementation in modern C++. + * Copyright (C) 2023 Clyne Sullivan + * + * 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 . + */ + +#ifndef ALEEFORTH_STATE_HPP +#define ALEEFORTH_STATE_HPP + +#include "dictionary.hpp" +#include "types.hpp" + +#include +#include + +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(Error::push)); + *++dsp = value; + } + + inline Cell pop() { + if (dsp < dstack) + std::longjmp(jmpbuf, static_cast(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(Error::pushr)); + *++rsp = value; + } + + inline Cell popr() { + if (rsp < rstack) + std::longjmp(jmpbuf, static_cast(Error::popr)); + return *rsp--; + } + + inline Cell& top() { + if (dsp < dstack) + std::longjmp(jmpbuf, static_cast(Error::top)); + return *dsp; + } + + inline Cell& pick(std::size_t i) { + if (dsp - i < dstack) + std::longjmp(jmpbuf, static_cast(Error::pick)); + return *(dsp - i); + } +}; + +#endif // ALEEFORTH_STATE_HPP + diff --git a/libalee/types.hpp b/libalee/types.hpp new file mode 100644 index 0000000..530ff4f --- /dev/null +++ b/libalee/types.hpp @@ -0,0 +1,44 @@ +/** + * Alee Forth: A portable and concise Forth implementation in modern C++. + * Copyright (C) 2023 Clyne Sullivan + * + * 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 . + */ + +#ifndef ALEEFORTH_TYPES_HPP +#define ALEEFORTH_TYPES_HPP + +#include + +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 + diff --git a/memdict.hpp b/memdict.hpp index c8ccce0..398af0f 100644 --- a/memdict.hpp +++ b/memdict.hpp @@ -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 index 44b5cec..0000000 --- a/parser.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Alee Forth: A portable and concise Forth implementation in modern C++. - * Copyright (C) 2023 Clyne Sullivan - * - * 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 . - */ - -#include "corewords.hpp" -#include "parser.hpp" - -#include -#include - -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(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(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 index 4b14d64..0000000 --- a/parser.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Alee Forth: A portable and concise Forth implementation in modern C++. - * Copyright (C) 2023 Clyne Sullivan - * - * 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 . - */ - -#ifndef ALEEFORTH_PARSER_HPP -#define ALEEFORTH_PARSER_HPP - -#include "types.hpp" - -#include - -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/splitmemdict.hpp b/splitmemdict.hpp index 083ce53..6631947 100644 --- a/splitmemdict.hpp +++ b/splitmemdict.hpp @@ -19,7 +19,7 @@ #ifndef ALEEFORTH_SPLITMEMDICT_HPP #define ALEEFORTH_SPLITMEMDICT_HPP -#include "dictionary.hpp" +#include "alee.hpp" #include diff --git a/state.cpp b/state.cpp deleted file mode 100644 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 - * - * 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 . - */ - -#include "corewords.hpp" -#include "state.hpp" - -#include - -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(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(dsp)) + 1; -} - -std::size_t State::rsize() const noexcept -{ - return std::distance(rstack, static_cast(rsp)) + 1; -} - diff --git a/state.hpp b/state.hpp deleted file mode 100644 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 - * - * 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 . - */ - -#ifndef ALEEFORTH_STATE_HPP -#define ALEEFORTH_STATE_HPP - -#include "dictionary.hpp" -#include "types.hpp" - -#include -#include - -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(Error::push)); - *++dsp = value; - } - - inline Cell pop() { - if (dsp < dstack) - std::longjmp(jmpbuf, static_cast(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(Error::pushr)); - *++rsp = value; - } - - inline Cell popr() { - if (rsp < rstack) - std::longjmp(jmpbuf, static_cast(Error::popr)); - return *rsp--; - } - - inline Cell& top() { - if (dsp < dstack) - std::longjmp(jmpbuf, static_cast(Error::top)); - return *dsp; - } - - inline Cell& pick(std::size_t i) { - if (dsp - i < dstack) - std::longjmp(jmpbuf, static_cast(Error::pick)); - return *(dsp - i); - } -}; - -#endif // ALEEFORTH_STATE_HPP - diff --git a/types.hpp b/types.hpp deleted file mode 100644 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 - * - * 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 . - */ - -#ifndef ALEEFORTH_TYPES_HPP -#define ALEEFORTH_TYPES_HPP - -#include - -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 - -- cgit v1.2.3