diff --git a/Makefile b/Makefile index 5b7f486..6d733e8 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ SRC := $(wildcard source/*.cpp) OBJ := $(subst .cpp,.o,$(SRC)) -CXXFLAGS += -std=c++20 -ggdb -g3 -O0 \ +CXXFLAGS += -std=c++20 -ggdb -g3 -Os \ -Wall -Wextra -pedantic \ -Isource diff --git a/source/core.cpp b/source/core.cpp index e2da109..437c700 100644 --- a/source/core.cpp +++ b/source/core.cpp @@ -1,5 +1,5 @@ // sprit-forth: A portable subroutine-threaded Forth. -// Copyright (C) 2023 Clyne Sullivan +// Copyright (C) 2024 Clyne Sullivan // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Library General Public License as published by @@ -16,36 +16,35 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. #include "core.hpp" -#include "state.hpp" #include #include +static State state; + void jump(FuncList ip) { // IP is incremented before its next execution. - IP = ip - 1; + Exec.ip = ip - 1; } -// LITERAL's run-time semantics: push the given value onto the stack. -static auto literall = WordWrap<[] { - push((Cell)*++IP); -}>; - void compileliteral() { - comma((Cell)literall); - comma(pop()); + // LITERAL's run-time semantics: push the given value onto the stack. + comma((Cell)WordWrap<[] { + Forth.push((Cell)*++Exec.ip); + }>); + comma(Forth.pop()); } bool haskey() { - return *((char *)&DICT[DIdxInBuf]) < DICT[DIdxSrcLen]; + return Forth.sourcei < Forth.sourceu; } void addkey(int k) { - auto addr = DICT[DIdxSource] + (DICT[DIdxSrcLen]++); + auto addr = Forth.source + Forth.sourceu++; auto ptr = reinterpret_cast(addr); *ptr = static_cast(k); } @@ -56,16 +55,16 @@ int key() while (!haskey()) getinput(); - auto ptr = reinterpret_cast(DICT[DIdxSource]); - int idx = (*((char *)&DICT[DIdxInBuf]))++; + auto ptr = reinterpret_cast(Forth.source); + int idx = Forth.sourcei++; return ptr[idx]; } Cell *comma(Cell n) { - const auto ptr = reinterpret_cast(HERE); + const auto ptr = reinterpret_cast(Forth.here); *ptr = n; - HERE += sizeof(Cell); + Forth.here += sizeof(Cell); return ptr; } @@ -76,7 +75,7 @@ Addr aligned(Addr addr) void align() { - HERE = aligned(HERE); + Forth.here = aligned(Forth.here); } static void readword(int ch) @@ -89,9 +88,9 @@ static void readword(int ch) // Collect the word's text. char *ptr; do { - ptr = reinterpret_cast(HERE); + ptr = reinterpret_cast(Forth.here); *ptr = k; - ++HERE; + ++Forth.here; if (!haskey()) break; @@ -100,36 +99,37 @@ static void readword(int ch) } while (k != ch); // Add a null terminator. - ptr = reinterpret_cast(HERE); + ptr = reinterpret_cast(Forth.here); *ptr = '\0'; - ++HERE; + ++Forth.here; } void word() { - auto here = (char *)HERE; - ++HERE; + auto here = (char *)Forth.here; + ++Forth.here; - readword(*sp()); + readword(*Forth.sp); here[0] = strlen(here + 1); - HERE = (Cell)here; - *sp() = HERE; + Forth.here = (Cell)here; + *Forth.sp = Forth.here; } void colon() { // Collect (and store) the word's name. align(); - auto name = HERE; + auto name = Forth.here; readword(' '); align(); // Build the Word structure. - comma(HERE + 4 * sizeof(Cell)); // exec ptr - comma(name); // name ptr - push((Cell)comma(0)); // link (to be set by semic()) - comma(0); // immediate + Forth.push(Forth.here); + comma(Forth.here + 4 * sizeof(Cell)); // exec ptr + comma(name); // name ptr + comma(0); // link + comma(0); // immediate // The word's execution begins with a prologue that technically performs // the "call" to this word. @@ -137,16 +137,15 @@ void colon() // about if it is running words or routines (i.e. pre-defined words). comma((Cell)+[](FuncList *ip) { ++ip; - rpush((Cell)IP); + Forth.rpush((Cell)Exec.ip); jump((FuncList)*ip); }); // The actual function list will begin one Cell beyond here. - comma(HERE + sizeof(Cell)); - - DICT[DIdxCompXt] = *sp() - 2 * sizeof(Cell); + comma(Forth.here + sizeof(Cell)); // Enter compiling state. - STATE = -1; + Forth.compxt = *Forth.sp; + Forth.state = -1; } void semic() @@ -155,27 +154,26 @@ void semic() comma((Cell)fexit); // Complete the new word's linkage to make it usable. - auto link = (Cell *)pop(); - *link = LATEST; - LATEST = (Cell)(link - 2); + auto word = reinterpret_cast(Forth.pop()); + Forth.add(*word); // Exit compilation state. - STATE = 0; + Forth.state = 0; } // TODO define in Forth? ": ' bl word find drop ;" void tick() { // Get the name to look up. - auto name = (char *)HERE; + auto name = Forth.here; readword(' '); // Look up the name and push the result. - int len = HERE - (Cell)name - 1; - auto word = find(name, len); - push((Cell)word); + int len = Forth.here - name - 1; + auto word = Forth.find((char *)name, len); + Forth.push((Cell)word); // Deallocate `name`. - HERE = (Cell)name; + Forth.here = name; } diff --git a/source/core.hpp b/source/core.hpp index 8b220e4..935fc0c 100644 --- a/source/core.hpp +++ b/source/core.hpp @@ -1,5 +1,5 @@ // sprit-forth: A portable subroutine-threaded Forth. -// Copyright (C) 2023 Clyne Sullivan +// Copyright (C) 2024 Clyne Sullivan // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Library General Public License as published by @@ -18,7 +18,8 @@ #ifndef CORE_HPP #define CORE_HPP -#include "types.hpp" +#include "executor.hpp" +#include "state.hpp" /** * To be implemented by the user: Adds available input to the source buffer. @@ -30,9 +31,7 @@ extern void getinput(); * "Function exit" word, analagous to a function's return statement. */ constexpr auto fexit = WordWrap<[] { - extern FuncList IP; - extern Cell rpop(); - IP = reinterpret_cast(rpop()); + Exec.ip = reinterpret_cast(Forth.rpop()); }>; void jump(FuncList ip); /** Jumps to the given instruction pointer. */ diff --git a/source/executor.cpp b/source/executor.cpp new file mode 100644 index 0000000..d86abed --- /dev/null +++ b/source/executor.cpp @@ -0,0 +1,75 @@ +// sprit-forth: A portable subroutine-threaded Forth. +// Copyright (C) 2024 Clyne Sullivan +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published by +// the Free Software Foundation; either version 2 of the License, or (at your +// option) any later version. +// +// This library 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 Library General Public License for +// more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +#include "executor.hpp" + +Executor Exec; + +Error Executor::executor(FuncList *list) noexcept +{ + auto result = static_cast(setjmp(jmpbuf)); + FuncList body; + + if (static_cast(result) == 0) { + result = Error::none; + + // We are given the pointer to a list of function pointers. + // Dereference once to retrieve the function pointer list. + // We do not work with IP initially since it needs to be set to zero if + // this is a top-level call/execution. + body = *list; + + // Enter the execution loop. + goto entry; + + // Execution continues so long as IP is not zero. + // If this is a top-level execution of a pre-defined word, then IP will + // remain zero'd and the loop will immediately exit. + // If this is a defined word's execution, then its "call" will overwrite + // IP (and push the initial zero-IP to the return stack); execution will + // continue until we return to the zero-IP. + while (ip) { + // Retrieve next function pointer list. + body = (FuncList)*++ip; +entry: + // Dereference `body` to get the first function in the list. + // This is casted to take a FuncList as an argument since defined + // words need to know their addresses so that they can perform + // their "calls". + // If the word is pre-defined then the argument will simply be + // ignored. + auto func = (void (*)(FuncList))*body; + func(body); + } + } + + return result; +} + +Error Executor::execute1(Word *word) noexcept +{ + // IP must initially be zero if executing a word at the top level. + ip = nullptr; + return executor(&word->list); +} + +[[noreturn]] +void Executor::terminate(Error error) noexcept +{ + std::longjmp(jmpbuf, static_cast(error)); +} + diff --git a/source/executor.hpp b/source/executor.hpp new file mode 100644 index 0000000..2029080 --- /dev/null +++ b/source/executor.hpp @@ -0,0 +1,53 @@ +// sprit-forth: A portable subroutine-threaded Forth. +// Copyright (C) 2024 Clyne Sullivan +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published by +// the Free Software Foundation; either version 2 of the License, or (at your +// option) any later version. +// +// This library 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 Library General Public License for +// more details. +// +// You should have received a copy of the GNU Library General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifndef EXECUTOR_HPP +#define EXECUTOR_HPP + +#include "types.hpp" + +#include + +class Executor +{ + std::jmp_buf jmpbuf; + +public: + FuncList ip = nullptr; + + /** + * Begins execution with the given function pointer list. + * @param list Function pointer list to execute + */ + [[nodiscard]] + Error executor(FuncList *list) noexcept; + + /** + * Executes the given word by calling executor on its definition. + * @param word The word to execute + */ + [[nodiscard]] + Error execute1(Word *word) noexcept; + + [[noreturn]] + void terminate(Error error) noexcept; +}; + +extern Executor Exec; + +#endif // EXECUTOR_HPP + diff --git a/source/parse.cpp b/source/parse.cpp index 27c514d..6e1d2bf 100644 --- a/source/parse.cpp +++ b/source/parse.cpp @@ -1,5 +1,5 @@ // sprit-forth: A portable subroutine-threaded Forth. -// Copyright (C) 2023 Clyne Sullivan +// Copyright (C) 2024 Clyne Sullivan // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Library General Public License as published by @@ -16,6 +16,7 @@ // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. #include "core.hpp" +#include "executor.hpp" #include "state.hpp" #include "types.hpp" @@ -34,16 +35,16 @@ static Error parseword(const char *start, const char *end) auto result = Error::none; if (start != end) { - if (auto word = find(start, end - start); word) { - if (!word->immediate() && STATE) { + if (auto word = Forth.find(start, end - start); word) { + if (!word->immediate() && Forth.state) { comma((Cell)word->list); } else { - result = execute1(word); + result = Exec.execute1(word); } } else if (isdigit(*start) || (*start == '-' && isdigit(*(start + 1)))) { - push(std::atoi(start)); + Forth.push(std::atoi(start)); - if (STATE) + if (Forth.state) compileliteral(); } else if (findword(start, end - start)) { return Error::noword; @@ -57,11 +58,11 @@ static Error parseword(const char *start, const char *end) static Error parseSource() { auto result = Error::none; - char *start = (char *)DICT[DIdxSource]; + char *start = (char *)Forth.source; char *end = start; - auto& i = *((char *)&DICT[DIdxInBuf]); + auto& i = *((char *)&Forth.sourcei); - while (result == Error::none && i < DICT[DIdxSrcLen]) { + while (result == Error::none && i < Forth.sourceu) { if (isspace(*end) || *end == '\0') { if (end - start < 1) { start = ++end; @@ -69,7 +70,7 @@ static Error parseSource() } else { ++i; // discard the space result = parseword(start, end); - start = (char *)DICT[DIdxSource] + i; + start = (char *)Forth.source + i; end = start; } } else { @@ -85,9 +86,9 @@ static Error parseSource() Error parse() { // Reset source buffer and try to fill it with getinput(). - DICT[DIdxSource] = (Cell)&DICT[DIdxInBuf] + 1; - DICT[DIdxSrcLen] = 0; - *((char *)&DICT[DIdxInBuf]) = 0; + Forth.source = (Cell)&Forth.sourcei + 1; + Forth.sourceu = 0; + Forth.sourcei = 0; getinput(); addkey('\0'); diff --git a/source/parse.hpp b/source/parse.hpp index 757cdae..0f97944 100644 --- a/source/parse.hpp +++ b/source/parse.hpp @@ -1,5 +1,5 @@ // sprit-forth: A portable subroutine-threaded Forth. -// Copyright (C) 2023 Clyne Sullivan +// Copyright (C) 2024 Clyne Sullivan // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Library General Public License as published by diff --git a/source/state.cpp b/source/state.cpp index 03ad95d..63c633a 100644 --- a/source/state.cpp +++ b/source/state.cpp @@ -1,5 +1,5 @@ // sprit-forth: A portable subroutine-threaded Forth. -// Copyright (C) 2023 Clyne Sullivan +// Copyright (C) 2024 Clyne Sullivan // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Library General Public License as published by @@ -18,108 +18,41 @@ #include "core.hpp" #include "state.hpp" -#include #include -FuncList IP = nullptr; -std::array DICT; +State Forth; -Cell& BASE = DICT[DIdxBase]; -Cell& HERE = DICT[DIdxHere]; -Cell& LATEST = DICT[DIdxLatest]; -Cell& STATE = DICT[DIdxState]; +void State::push(Cell value) { + if (sp >= ds.end()) + Exec.terminate(Error::push); -static std::jmp_buf jmpbuf; -static Cell *SP = DICT.data() + DICT.size() - DS; -static Cell *RP = DICT.data() + DICT.size() - DS - RS; - -void push(Cell value) { - if (SP >= DICT.data() + DICT.size()) - std::longjmp(jmpbuf, static_cast(Error::push)); - - *++SP = value; + *++sp = value; } -Cell pop() { - if (SP - 1 < DICT.data() + DICT.size() - DS) - std::longjmp(jmpbuf, static_cast(Error::pop)); +Cell State::pop() { + if (sp - 1 < ds.begin()) + Exec.terminate(Error::pop); - return *SP--; + return *sp--; } -Cell *sp() { - return SP; -} - -void rpush(Cell value) { - if (RP >= DICT.data() + DICT.size() - DS) - std::longjmp(jmpbuf, static_cast(Error::rpush)); - - *++RP = value; -} - -Cell rpop() { - if (RP - 1 < DICT.data() + DICT.size() - DS - RS) - std::longjmp(jmpbuf, static_cast(Error::rpop)); - - return *RP--; -} +void State::rpush(Cell value) { + if (rp >= rs.end()) + Exec.terminate(Error::rpush); -Cell *rp() { - return RP; + *++rp = value; } -Error executor(FuncList *list) -{ - auto result = static_cast(setjmp(jmpbuf)); - FuncList body; - - if (static_cast(result) == 0) { - result = Error::none; - - // We are given the pointer to a list of function pointers. - // Dereference once to retrieve the function pointer list. - // We do not work with IP initially since it needs to be set to zero if - // this is a top-level call/execution. - body = *list; +Cell State::rpop() { + if (rp - 1 < rs.begin()) + Exec.terminate(Error::rpop); - // Enter the execution loop. - goto entry; - - // Execution continues so long as IP is not zero. - // If this is a top-level execution of a pre-defined word, then IP will - // remain zero'd and the loop will immediately exit. - // If this is a defined word's execution, then its "call" will overwrite - // IP (and push the initial zero-IP to the return stack); execution will - // continue until we return to the zero-IP. - while (IP) { - // Retrieve next function pointer list. - body = (FuncList)*++IP; -entry: - // Dereference `body` to get the first function in the list. - // This is casted to take a FuncList as an argument since defined - // words need to know their addresses so that they can perform - // their "calls". - // If the word is pre-defined then the argument will simply be - // ignored. - auto func = (void (*)(FuncList))*body; - func(body); - } - } - - return result; -} - -Error execute1(Word *word) -{ - // IP must initially be zero if executing a word at the top level. - IP = 0; - return executor(&word->list); + return *rp--; } -Word *find(const char *s, int len) +Word *State::find(const char *s, int len) { - for (auto w = (Word *)LATEST; w; w = w->link) { + for (auto w = latest; w; w = w->link) { if (len == (int)strlen(w->name) && strncmp(s, w->name, len) == 0) return w; } diff --git a/source/state.hpp b/source/state.hpp index b6e5bcf..5667875 100644 --- a/source/state.hpp +++ b/source/state.hpp @@ -1,5 +1,5 @@ // sprit-forth: A portable subroutine-threaded Forth. -// Copyright (C) 2023 Clyne Sullivan +// Copyright (C) 2024 Clyne Sullivan // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Library General Public License as published by @@ -34,58 +34,60 @@ constexpr Addr DIdxSrcLen = 6; constexpr Addr DIdxInBuf = 7; constexpr Addr DIdxBegin = DIdxInBuf + 80 * sizeof(char); -/** - * Memory chunk used to store the dictoinary and stacks. - */ -extern std::array DICT; +class State +{ + /** + * Memory chunk used to store the dictoinary and stacks. + */ + std::array dict; + std::array ds; + std::array rs; -extern Cell& BASE; -extern Cell& HERE; /** Linked to HERE's storage in DICT. */ -extern Cell& LATEST; /** Linked to LATEST's storage in DICT. */ -extern Cell& STATE; /** Linked to STATE's storage in DICT. */ -extern FuncList IP; /** Instruction pointer */ +public: + Cell *sp = ds.begin(); + Cell *rp = rs.begin(); + Cell& base = dict[DIdxBase]; + Cell& here = dict[DIdxHere]; + Word *& latest = *(Word **)&dict[DIdxLatest]; + Cell& state = dict[DIdxState]; + Cell& compxt = dict[DIdxCompXt]; + Cell& source = dict[DIdxSource]; + Cell& sourceu = dict[DIdxSrcLen]; + unsigned char& sourcei = *(unsigned char *)&dict[DIdxInBuf]; -void push(Cell); -[[nodiscard]] Cell pop(); -[[nodiscard]] Cell *sp(); + State() { + dict[DIdxBase] = 10; + dict[DIdxHere] = (Cell)&dict[DIdxBegin]; + dict[DIdxLatest] = 0;//(Cell)&wordset.back(); + dict[DIdxState] = 0; + } -void rpush(Cell); -[[nodiscard]] Cell rpop(); -[[nodiscard]] Cell *rp(); + void add(Word& word) noexcept { + word.link = latest; + latest = &word; + } -/** - * Initializes the dictionary to default values. - * @param wordset The initial WordSet of pre-defined words. - */ -inline void initialize(const auto& wordset) -{ - DICT[DIdxBase] = 10; - DICT[DIdxHere] = (Cell)&DICT[DIdxBegin]; - DICT[DIdxLatest] = (Cell)wordset.latest; - DICT[DIdxState] = 0; -} + auto dictdata() noexcept { + return dict.data(); + } + + void push(Cell); + [[nodiscard]] Cell pop(); -/** - * Begins execution with the given function pointer list. - * @param list Function pointer list to execute - */ -[[nodiscard]] -Error executor(FuncList *list); + void rpush(Cell); + [[nodiscard]] Cell rpop(); -/** - * Executes the given word by calling executor on its definition. - * @param word The word to execute - */ -[[nodiscard]] -Error execute1(Word *word); + /** + * Looks up the definition of the given word. + * @param s The name of the word to find + * @param len The character count of the word's name + * @return Pointer to the word's definition or nullptr if not found + */ + [[nodiscard]] + Word *find(const char *s, int len); +}; -/** - * Looks up the definition of the given word. - * @param s The name of the word to find - * @param len The character count of the word's name - * @return Pointer to the word's definition or nullptr if not found - */ -Word *find(const char *s, int len); +extern State Forth; #endif // STATE_HPP diff --git a/source/types.hpp b/source/types.hpp index 0552135..aedc0d3 100644 --- a/source/types.hpp +++ b/source/types.hpp @@ -1,5 +1,5 @@ // sprit-forth: A portable subroutine-threaded Forth. -// Copyright (C) 2023 Clyne Sullivan +// Copyright (C) 2024 Clyne Sullivan // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Library General Public License as published by @@ -21,6 +21,7 @@ #include #include #include +#include using Cell = intptr_t; /** Type of a dictionary's cell. */ using Addr = uintptr_t; /** Type of a dictionary address. */ @@ -33,6 +34,16 @@ using FuncList = Func const *; /** Words are defined as a list of Func. */ static_assert(sizeof(Cell) == sizeof(Addr)); static_assert(sizeof(Cell) == sizeof(Func)); +/** + * Wraps the given functions so that a function pointer list can be created + * and used for a word's definition. + */ +template +constexpr auto WordWrap = []() noexcept { + constexpr static auto wrapper = +[] { (funcs(), ...); }; + return &wrapper; +}(); + /** * @struct Word * @brief Structure of a word's definition. @@ -69,42 +80,6 @@ static_assert(offsetof(Word, link) == 2 * sizeof(Cell)); static_assert(offsetof(Word, imm) == 3 * sizeof(Cell)); static_assert(sizeof(Word) == 4 * sizeof(Cell)); -/** - * @struct WordSet - * @brief Groups a set of pre-defined words and links them. - */ -template -struct WordSet -{ - std::array words; - Word *latest; - - /** - * Stores the given pre-defined words into the `words` array and links - * their definitions together. The resulting `latest` value can be used - * to set the global LATEST. - */ - constexpr WordSet(Words... ws): - words {ws...} - { - auto it = words.begin(); - while (++it != words.end()) - it->link = it - 1; - - latest = &*words.rbegin(); - } -}; - -/** - * Wraps the given functions so that a function pointer list can be created - * and used for a word's definition. - */ -template -constexpr auto WordWrap = []() noexcept { - constexpr static auto wrapper = +[] { (funcs(), ...); }; - return &wrapper; -}(); - enum class Error : int { none = 1, push, diff --git a/sprit.cpp b/sprit.cpp index 7b36d2f..faab084 100644 --- a/sprit.cpp +++ b/sprit.cpp @@ -1,5 +1,5 @@ // sprit-forth: A portable subroutine-threaded Forth. -// Copyright (C) 2023 Clyne Sullivan +// Copyright (C) 2024 Clyne Sullivan // // This library is free software; you can redistribute it and/or modify it // under the terms of the GNU Library General Public License as published by @@ -27,66 +27,66 @@ // TODO: // sys m* _/ _% _' depth _rdepth _in _ev find _uma u< um/mod -static void peek() { *sp() = *(Cell *)(*sp()); } -static void commaSP() { comma(pop()); } -static void discard() { auto v = pop(); (void)v; } -static void tobool() { if (*sp()) *sp() = -1; } +static void peek() { *Forth.sp = *(Cell *)(*Forth.sp); } +static void commaSP() { comma(Forth.pop()); } +static void discard() { auto v = Forth.pop(); (void)v; } +static void tobool() { if (*Forth.sp) *Forth.sp = -1; } -constinit WordSet words ( - Word("[", WordWrap<[] { STATE = 0; }>).markImmediate(), - Word("]", WordWrap<[] { STATE = -1; }>), +constinit std::array words { + Word("[", WordWrap<[] { Forth.state = 0; }>).markImmediate(), + Word("]", WordWrap<[] { Forth.state = -1; }>), Word("@", WordWrap), - Word("c@", WordWrap), - Word("!", WordWrap<[] { auto a = (Cell *)pop(); *a = pop(); }>), - Word("c!", WordWrap<[] { auto a = (char *)pop(); *a = pop(); }>), - Word("_d", WordWrap<[] { *sp() += (Cell)DICT.data(); }>), - Word("_jmp", WordWrap<[] { jump((FuncList)*++IP); }>), + Word("c@", WordWrap), + Word("!", WordWrap<[] { auto a = (Cell *)Forth.pop(); *a = Forth.pop(); }>), + Word("c!", WordWrap<[] { auto a = (char *)Forth.pop(); *a = Forth.pop(); }>), + Word("_d", WordWrap<[] { *Forth.sp += (Cell)Forth.dictdata(); }>), + Word("_jmp", WordWrap<[] { jump((FuncList)*++Exec.ip); }>), Word("_jmp0", WordWrap<[] { - ++IP; - if (pop() == 0) - jump((FuncList)*IP); + ++Exec.ip; + if (Forth.pop() == 0) + jump((FuncList)*Exec.ip); }>), Word(",", WordWrap), - Word("emit", WordWrap<[] { std::putchar(pop()); }>), - Word("key", WordWrap<[] { push(key()); }>), - Word("key?", WordWrap<[] { push(haskey()); }, tobool>), - Word("execute", WordWrap<[] { (void)executor((FuncList *)pop()); }>), + Word("emit", WordWrap<[] { std::putchar(Forth.pop()); }>), + Word("key", WordWrap<[] { Forth.push(key()); }>), + Word("key?", WordWrap<[] { Forth.push(haskey()); }, tobool>), + Word("execute", WordWrap<[] { (void)Exec.executor((FuncList *)Forth.pop()); }>), Word(":", WordWrap), Word(";", WordWrap).markImmediate(), Word("exit", fexit), Word("drop", WordWrap), - Word("dup", WordWrap<[] { push(*sp()); }>), - Word("swap", WordWrap<[] { std::swap(*sp(), *(sp() - 1)); }>), - Word("pick", WordWrap<[] { auto t = *(sp() - *sp() - 1); *sp() = t; }>), - Word("cells", WordWrap<[] { *sp() *= sizeof(Cell); }>), - Word("+", WordWrap<[] { *(sp() - 1) += *sp(); }, discard>), - Word("-", WordWrap<[] { *(sp() - 1) -= *sp(); }, discard>), - Word("*", WordWrap<[] { *(sp() - 1) *= *sp(); }, discard>), - Word("/", WordWrap<[] { *(sp() - 1) /= *sp(); }, discard>), - Word("mod", WordWrap<[] { *(sp() - 1) %= *sp(); }, discard>), - Word("=", WordWrap<[] { *(sp() - 1) = *(sp() - 1) == *sp(); }, discard, tobool>), - Word("<", WordWrap<[] { *(sp() - 1) = *(sp() - 1) < *sp(); }, discard, tobool>), - Word("or", WordWrap<[] { *(sp() - 1) |= *sp(); }, discard>), - Word("and", WordWrap<[] { *(sp() - 1) &= *sp(); }, discard>), - Word("xor", WordWrap<[] { *(sp() - 1) ^= *sp(); }, discard>), - Word("lshift", WordWrap<[] { *(sp() - 1) <<= *sp(); }, discard>), - Word("rshift", WordWrap<[] { *(sp() - 1) >>= *sp(); }, discard>), - Word(">r", WordWrap<[] { rpush(pop()); }>), - Word("r>", WordWrap<[] { push(rpop()); }>), - Word("immediate", WordWrap<[] { ((Word *)LATEST)->markImmediate(); }>), - Word("aligned", WordWrap<[] { *sp() = aligned(*sp()); }>), + Word("dup", WordWrap<[] { Forth.push(*Forth.sp); }>), + Word("swap", WordWrap<[] { std::swap(*Forth.sp, *(Forth.sp - 1)); }>), + Word("pick", WordWrap<[] { auto t = *(Forth.sp - *Forth.sp - 1); *Forth.sp = t; }>), + Word("cells", WordWrap<[] { *Forth.sp *= sizeof(Cell); }>), + Word("+", WordWrap<[] { *(Forth.sp - 1) += *Forth.sp; }, discard>), + Word("-", WordWrap<[] { *(Forth.sp - 1) -= *Forth.sp; }, discard>), + Word("*", WordWrap<[] { *(Forth.sp - 1) *= *Forth.sp; }, discard>), + Word("/", WordWrap<[] { *(Forth.sp - 1) /= *Forth.sp; }, discard>), + Word("mod", WordWrap<[] { *(Forth.sp - 1) %= *Forth.sp; }, discard>), + Word("=", WordWrap<[] { *(Forth.sp - 1) = *(Forth.sp - 1) == *Forth.sp; }, discard, tobool>), + Word("<", WordWrap<[] { *(Forth.sp - 1) = *(Forth.sp - 1) < *Forth.sp; }, discard, tobool>), + Word("or", WordWrap<[] { *(Forth.sp - 1) |= *Forth.sp; }, discard>), + Word("and", WordWrap<[] { *(Forth.sp - 1) &= *Forth.sp; }, discard>), + Word("xor", WordWrap<[] { *(Forth.sp - 1) ^= *Forth.sp; }, discard>), + Word("lshift", WordWrap<[] { *(Forth.sp - 1) <<= *Forth.sp; }, discard>), + Word("rshift", WordWrap<[] { *(Forth.sp - 1) >>= *Forth.sp; }, discard>), + Word(">r", WordWrap<[] { Forth.rpush(Forth.pop()); }>), + Word("r>", WordWrap<[] { Forth.push(Forth.rpop()); }>), + Word("immediate", WordWrap<[] { Forth.latest->markImmediate(); }>), + Word("aligned", WordWrap<[] { *Forth.sp = aligned(*Forth.sp); }>), Word("align", WordWrap), - Word("literal", WordWrap<[] { if (STATE) compileliteral(); }>).markImmediate(), + Word("literal", WordWrap<[] { if (Forth.state) compileliteral(); }>).markImmediate(), Word("\'", WordWrap), - Word("_i", WordWrap<[] { *sp() = ((Word *)*sp())->immediate(); }, tobool>), + Word("_i", WordWrap<[] { *Forth.sp = ((Word *)*Forth.sp)->immediate(); }, tobool>), Word("[']", WordWrap).markImmediate(), Word("compile,", WordWrap), Word("word", WordWrap), Word("_b", WordWrap<[] { std::putchar('#'); // Gives a good breakpoint spot for gdb }>), - Word(".", WordWrap<[] { std::cout << pop() << ' '; }>) -); + Word(".", WordWrap<[] { std::cout << Forth.pop() << ' '; }>) +}; void getinput() { @@ -100,13 +100,13 @@ void getinput() int main() { - initialize(words); + std::for_each(words.begin(), words.end(), [](Word& w) { Forth.add(w); }); while (std::cin.good()) { auto result = parse(); if (result == Error::none) - std::cout << (STATE ? "compiled" : "ok") << std::endl; + std::cout << (Forth.state ? "compiled" : "ok") << std::endl; else std::cout << "error " << static_cast(result) << std::endl; }