refactor, encapsulate

main
Clyne 3 months ago
parent b82f1c1f7e
commit a79eaf8e16
Signed by: clyne
GPG Key ID: 1B74EE6C49C96795

@ -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

@ -1,5 +1,5 @@
// sprit-forth: A portable subroutine-threaded Forth.
// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// 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 <cctype>
#include <cstring>
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<char *>(addr);
*ptr = static_cast<char>(k);
}
@ -56,16 +55,16 @@ int key()
while (!haskey())
getinput();
auto ptr = reinterpret_cast<char *>(DICT[DIdxSource]);
int idx = (*((char *)&DICT[DIdxInBuf]))++;
auto ptr = reinterpret_cast<char *>(Forth.source);
int idx = Forth.sourcei++;
return ptr[idx];
}
Cell *comma(Cell n)
{
const auto ptr = reinterpret_cast<Cell *>(HERE);
const auto ptr = reinterpret_cast<Cell *>(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<char *>(HERE);
ptr = reinterpret_cast<char *>(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<char *>(HERE);
ptr = reinterpret_cast<char *>(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<Word *>(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;
}

@ -1,5 +1,5 @@
// sprit-forth: A portable subroutine-threaded Forth.
// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// 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<FuncList>(rpop());
Exec.ip = reinterpret_cast<FuncList>(Forth.rpop());
}>;
void jump(FuncList ip); /** Jumps to the given instruction pointer. */

@ -0,0 +1,75 @@
// sprit-forth: A portable subroutine-threaded Forth.
// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// 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<Error>(setjmp(jmpbuf));
FuncList body;
if (static_cast<int>(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<int>(error));
}

@ -0,0 +1,53 @@
// sprit-forth: A portable subroutine-threaded Forth.
// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// 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 <csetjmp>
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

@ -1,5 +1,5 @@
// sprit-forth: A portable subroutine-threaded Forth.
// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// 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');

@ -1,5 +1,5 @@
// sprit-forth: A portable subroutine-threaded Forth.
// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// 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

@ -1,5 +1,5 @@
// sprit-forth: A portable subroutine-threaded Forth.
// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// 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 <csetjmp>
#include <cstring>
FuncList IP = nullptr;
std::array<Cell, DictSize> 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<int>(Error::push));
*++SP = value;
*++sp = value;
}
Cell pop() {
if (SP - 1 < DICT.data() + DICT.size() - DS)
std::longjmp(jmpbuf, static_cast<int>(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<int>(Error::rpush));
*++RP = value;
}
Cell rpop() {
if (RP - 1 < DICT.data() + DICT.size() - DS - RS)
std::longjmp(jmpbuf, static_cast<int>(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<Error>(setjmp(jmpbuf));
FuncList body;
if (static_cast<int>(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;
}

@ -1,5 +1,5 @@
// sprit-forth: A portable subroutine-threaded Forth.
// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// 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<Cell, DictSize> DICT;
class State
{
/**
* Memory chunk used to store the dictoinary and stacks.
*/
std::array<Cell, DictSize> dict;
std::array<Cell, DS> ds;
std::array<Cell, RS> 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

@ -1,5 +1,5 @@
// sprit-forth: A portable subroutine-threaded Forth.
// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// 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 <array>
#include <cstddef>
#include <cstdint>
#include <memory>
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<auto... funcs>
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<typename... Words>
struct WordSet
{
std::array<Word, sizeof...(Words)> 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<auto... funcs>
constexpr auto WordWrap = []() noexcept {
constexpr static auto wrapper = +[] { (funcs(), ...); };
return &wrapper;
}();
enum class Error : int {
none = 1,
push,

@ -1,5 +1,5 @@
// sprit-forth: A portable subroutine-threaded Forth.
// Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
//
// 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<peek>),
Word("c@", WordWrap<peek, [] { *sp() &= 0xFF; }>),
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<peek, [] { *Forth.sp &= 0xFF; }>),
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<commaSP>),
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<colon>),
Word(";", WordWrap<semic>).markImmediate(),
Word("exit", fexit),
Word("drop", WordWrap<discard>),
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<align>),
Word("literal", WordWrap<[] { if (STATE) compileliteral(); }>).markImmediate(),
Word("literal", WordWrap<[] { if (Forth.state) compileliteral(); }>).markImmediate(),
Word("\'", WordWrap<tick>),
Word("_i", WordWrap<[] { *sp() = ((Word *)*sp())->immediate(); }, tobool>),
Word("_i", WordWrap<[] { *Forth.sp = ((Word *)*Forth.sp)->immediate(); }, tobool>),
Word("[']", WordWrap<tick, compileliteral>).markImmediate(),
Word("compile,", WordWrap<peek, commaSP>),
Word("word", WordWrap<word>),
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<int>(result) << std::endl;
}

Loading…
Cancel
Save