compact implementation; runs on msp430

llvm
Clyne 2 years ago
parent 914a75b209
commit 0b88b4596e
Signed by: clyne
GPG Key ID: 3267C8EBF3F9AFC7

1
.gitignore vendored

@ -1,4 +1,5 @@
.*
*.o
alee
alee-msp430
libalee.a

@ -1,24 +1,32 @@
CXXFLAGS += -std=c++17 -g3 -ggdb -O0 \
-Wall -Wextra -pedantic -Wno-vla -Werror
-Wall -Wextra -pedantic -Werror \
-fno-exceptions -fno-rtti #-fstack-usage
CXXFILES := corewords.cpp dictionary.cpp parser.cpp state.cpp
OBJFILES := $(subst .cpp,.o,$(CXXFILES))
LIBFILE := libalee.a
EXEFILE := alee
all: $(EXEFILE)
all: alee
msp430: CXX := msp430-elf32-g++
msp430: AR := msp430-elf32-ar
msp430: CXXFLAGS += -Os -mmcu=msp430g2553 -ffunction-sections -fdata-sections -DMEMDICTSIZE=200
msp430: LDFLAGS += -L/opt/msp430-elf32/include -Wl,-gc-sections
msp430: alee-msp430
small: CXXFLAGS += -Os
small: $(EXEFILE)
small: alee
fast: CXXFLAGS += -O3 -march=native -mtune=native
fast: $(EXEFILE)
fast: alee
alee: $(LIBFILE)
$(EXEFILE): $(LIBFILE)
alee-msp430: $(LIBFILE)
$(LIBFILE): $(OBJFILES)
$(AR) cr $@ $(OBJFILES)
clean:
rm -f $(EXEFILE) $(LIBFILE) $(OBJFILES)
rm -f alee alee-msp430 $(LIBFILE) $(OBJFILES)

@ -0,0 +1,162 @@
/**
* Alee Forth: A portable and concise Forth implementation in modern C++.
* Copyright (C) 2023 Clyne Sullivan <clyne@bitgloo.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "alee.hpp"
#include "memdict.hpp"
#include <msp430.h>
static char strbuf[32];
static void readchar(State& state);
static void serput(int c);
static void serputs(const char *s);
static void printint(int n, char *buf);
int main()
{
WDTCTL = WDTPW | WDTHOLD;
DCOCTL = 0;
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
P1SEL |= BIT1 | BIT2;
P1SEL2 |= BIT1 | BIT2;
UCA0CTL1 = UCSWRST;
UCA0CTL1 |= UCSSEL_2;
UCA0BR0 = 104;
UCA0BR1 = 0;
UCA0MCTL = UCBRS0;
UCA0CTL1 &= (uint8_t)~UCSWRST;
__enable_interrupt();
static MemDict dict;
State state (dict, readchar);
Parser parser;
dict.write(Dictionary::Base, 10);
dict.write(Dictionary::Latest, Dictionary::Begin);
dict.write(Dictionary::Compiling, 0);
dict.write(Dictionary::Postpone, 0);
serputs("alee forth\n\r");
auto ptr = strbuf;
while (1) {
if (IFG2 & UCA0RXIFG) {
char c = UCA0RXBUF;
serput(c);
if (c == '\r') {
*ptr = '\0';
serputs("\n\r");
if (auto r = parser.parse(state, strbuf); r == 0) {
serputs(state.compiling() ? " compiled" : " ok");
} else {
switch (r) {
case Parser::UnknownWord:
serputs("unknown word...");
break;
default:
break;
}
}
serputs("\n\r");
ptr = strbuf;
} else if (c == '\b') {
if (ptr > strbuf)
--ptr;
} else if (ptr < strbuf + sizeof(strbuf)) {
if (c >= 'A' && c <= 'Z')
c += 32;
*ptr++ = c;
}
}
}
return 0;
}
static void readchar(State& state)
{
auto len = state.dict.read(Dictionary::Input);
Addr addr = Dictionary::Input + sizeof(Cell) +
Dictionary::InputCells - len - 1;
for (Cell i = 0; i < len; ++i, ++addr)
state.dict.writebyte(addr, state.dict.readbyte(addr + 1));
while (!(IFG2 & UCA0RXIFG));
state.dict.writebyte(addr, UCA0RXBUF);
state.dict.write(Dictionary::Input, len + 1);
}
void serput(int c)
{
while (!(IFG2 & UCA0TXIFG));
UCA0TXBUF = (char)c;
}
void serputs(const char *s)
{
while (*s)
serput(*s++);
}
void printint(int n, char *buf)
{
char *ptr = buf;
bool neg = n < 0;
if (neg)
n = -n;
do {
*ptr++ = (char)(n % 10) + '0';
} while ((n /= 10));
if (neg)
serput('-');
do {
serput(*--ptr);
} while (ptr > buf);
serput(' ');
}
void user_sys(State& state)
{
switch (state.pop()) {
case 0:
printint(state.pop(), strbuf);
break;
case 1:
serput(state.pop());
break;
default:
break;
}
}

@ -26,7 +26,7 @@
static bool okay = false;
static void readchar(State& state);
static void parseLine(Parser&, State&, std::string_view);
static void parseLine(Parser&, State&, const std::string&);
static void parseFile(Parser&, State&, std::istream&);
int main(int argc, char *argv[])
@ -105,9 +105,9 @@ void user_sys(State& state)
}
}
void parseLine(Parser& parser, State& state, std::string_view line)
void parseLine(Parser& parser, State& state, const std::string& line)
{
if (auto r = parser.parse(state, line); r == 0) {
if (auto r = parser.parse(state, line.c_str()); r == 0) {
if (okay)
std::cout << (state.compiling() ? "compiled" : "ok") << std::endl;
} else {
@ -116,6 +116,7 @@ void parseLine(Parser& parser, State& state, std::string_view line)
std::cout << "word not found in: " << line << std::endl;
break;
default:
std::cout << "error: " << r << std::endl;
break;
}
}

@ -18,6 +18,9 @@
#include "corewords.hpp"
#include <cstring>
#include <utility>
void CoreWords::run(unsigned int index, State& state)
{
auto getword = [&state] {
@ -197,18 +200,19 @@ void CoreWords::run(unsigned int index, State& state)
}
}
int CoreWords::findi(std::string_view word)
int CoreWords::findi(const char *word)
{
const auto size = std::strlen(word);
std::size_t i;
int wordsi = 0;
std::string_view words (wordsarr, sizeof(wordsarr));
for (i = 0; i < words.size();) {
const auto end = words.find_first_of({"\0\1", 2}, i);
for (i = 0; i < sizeof(wordsarr);) {
auto end = i;
while (wordsarr[end] > '\1')
++end;
if (word == words.substr(i, end - i))
return words[end] == '\0' ? wordsi : (wordsi | Compiletime);
if (size == end - i && !std::strncmp(word, wordsarr + i, size))
return wordsarr[end] == '\0' ? wordsi : (wordsi | Compiletime);
++wordsi;
i = end + 1;
@ -222,13 +226,13 @@ int CoreWords::findi(State& state, Word word)
std::size_t i;
int wordsi = 0;
std::string_view words (wordsarr, sizeof(wordsarr));
for (i = 0; i < words.size();) {
const auto end = words.find_first_of({"\0\1", 2}, i);
for (i = 0; i < sizeof(wordsarr);) {
auto end = i;
while (wordsarr[end] > '\1')
++end;
if (state.dict.equal(word, words.substr(i, end - i)))
return words[end] == '\0' ? wordsi : (wordsi | Compiletime);
if (state.dict.equal(word, wordsarr + i, end - i))
return wordsarr[end] == '\0' ? wordsi : (wordsi | Compiletime);
++wordsi;
i = end + 1;

@ -22,8 +22,6 @@
#include "types.hpp"
#include "state.hpp"
#include <string_view>
void user_sys(State&);
class CoreWords
@ -34,7 +32,7 @@ public:
constexpr static Cell Immediate = (1 << 5);
constexpr static Cell Compiletime = (1 << 6);
static int findi(std::string_view);
static int findi(const char *);
static int findi(State&, Word);
static void run(unsigned int, State&);

@ -19,15 +19,16 @@
#include "dictionary.hpp"
#include <cctype>
#include <cstring>
Addr Dictionary::allot(Cell amount)
Addr Dictionary::allot(Cell amount) noexcept
{
Addr old = here;
here += amount;
return old;
}
void Dictionary::add(Cell value)
void Dictionary::add(Cell value) noexcept
{
write(allot(sizeof(Cell)), value);
}
@ -41,13 +42,13 @@ Addr Dictionary::aligned(Addr addr) const noexcept
return addr;
}
Addr Dictionary::alignhere()
Addr Dictionary::alignhere() noexcept
{
here = aligned(here);
return here;
}
void Dictionary::addDefinition(Word word)
void Dictionary::addDefinition(Word word) noexcept
{
add(word.size());
for (auto w = word.start; w != word.end; ++w)
@ -56,7 +57,7 @@ void Dictionary::addDefinition(Word word)
alignhere();
}
Addr Dictionary::find(Word word)
Addr Dictionary::find(Word word) noexcept
{
Addr lt = latest(), oldlt;
do {
@ -77,13 +78,13 @@ Addr Dictionary::find(Word word)
return 0;
}
Addr Dictionary::getexec(Addr addr)
Addr Dictionary::getexec(Addr addr) noexcept
{
const auto len = read(addr) & 0x1F;
return aligned(addr + sizeof(Cell) + len);
}
Word Dictionary::input()
Word Dictionary::input() noexcept
{
auto len = read(Dictionary::Input);
if (len != 0) {
@ -111,22 +112,22 @@ Word Dictionary::input()
return {};
}
bool Dictionary::equal(Word word, std::string_view sv) const
bool Dictionary::equal(Word word, const char *str, unsigned len) const noexcept
{
if (word.size() != sv.size())
if (word.size() != len)
return false;
for (auto w = word.start; w != word.end; ++w) {
if (readbyte(w) != sv.front())
if (readbyte(w) != *str)
return false;
sv = sv.substr(1);
++str;
}
return true;
}
bool Dictionary::equal(Word word, Word other) const
bool Dictionary::equal(Word word, Word other) const noexcept
{
if (word.size() != other.size())
return false;

@ -23,7 +23,6 @@
#include <cstddef>
#include <cstdint>
#include <string_view>
class Dictionary
{
@ -38,26 +37,26 @@ public:
Addr here = Begin;
Addr latest() { return read(Latest); }
void latest(Addr l) { write(Latest, l); }
Addr latest() const noexcept { return read(Latest); }
void latest(Addr l) noexcept { write(Latest, l); }
virtual Cell read(Addr) const = 0;
virtual void write(Addr, Cell) = 0;
virtual uint8_t readbyte(Addr) const = 0;
virtual void writebyte(Addr, uint8_t) = 0;
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();
Addr alignhere() noexcept;
Addr aligned(Addr) const noexcept;
Addr allot(Cell);
void add(Cell);
void addDefinition(Word);
Addr allot(Cell) noexcept;
void add(Cell) noexcept;
void addDefinition(Word) noexcept;
Addr find(Word);
Addr getexec(Addr);
Word input();
Addr find(Word) noexcept;
Addr getexec(Addr) noexcept;
Word input() noexcept;
bool equal(Word, std::string_view) const;
bool equal(Word, Word) const;
bool equal(Word, const char *, unsigned) const noexcept;
bool equal(Word, Word) const noexcept;
};
#endif // ALEEFORTH_DICTIONARY_HPP

@ -21,26 +21,29 @@
#include "dictionary.hpp"
constexpr unsigned long int MemDictSize = 4096;
#ifndef MEMDICTSIZE
#define MEMDICTSIZE (4096)
#endif
constexpr unsigned long int MemDictSize = MEMDICTSIZE;
class MemDict : public Dictionary
{
uint8_t dict[MemDictSize];
public:
virtual Cell read(Addr addr) const final {
virtual Cell read(Addr addr) const noexcept final {
return *reinterpret_cast<const Cell *>(dict + addr);
}
virtual void write(Addr addr, Cell value) final {
virtual void write(Addr addr, Cell value) noexcept final {
*reinterpret_cast<Cell *>(dict + addr) = value;
}
virtual uint8_t readbyte(Addr addr) const final {
virtual uint8_t readbyte(Addr addr) const noexcept final {
return dict[addr];
}
virtual void writebyte(Addr addr, uint8_t value) final {
virtual void writebyte(Addr addr, uint8_t value) noexcept final {
dict[addr] = value;
}
};

@ -19,17 +19,19 @@
#include "corewords.hpp"
#include "parser.hpp"
#include <cctype>
#include <cstdlib>
#include <charconv>
#include <cstring>
int Parser::parse(State& state, std::string_view& str)
int Parser::parse(State& state, const char *str)
{
const auto size = std::strlen(str);
auto addr = Dictionary::Input;
state.dict.write(addr, str.size() + 1);
state.dict.write(addr, size + 1);
addr += sizeof(Cell) + Dictionary::InputCells - str.size() - 1;
for (char c : str)
state.dict.writebyte(addr++, c);
addr += sizeof(Cell) + Dictionary::InputCells - size - 1;
while (*str)
state.dict.writebyte(addr++, *str++);
state.dict.writebyte(addr, ' ');
return parseSource(state);
@ -74,7 +76,8 @@ int Parser::parseWord(State& state, Word word)
} else if (state.compiling() && !imm) {
state.dict.add(ins);
} else {
state.execute(ins);
if (auto stat = state.execute(ins); stat != State::Error::none)
return static_cast<int>(stat);
}
return 0;
@ -88,11 +91,11 @@ int Parser::parseNumber(State& state, Word word)
buf[i] = state.dict.readbyte(word.start + i);
buf[i] = '\0';
char *p;
const auto base = state.dict.read(0);
const Cell l = std::strtol(buf, &p, base);
auto base = state.dict.read(0);
Cell l;
auto [ptr, ec] = std::from_chars(buf, buf + i, l, base);
if (static_cast<Addr>(std::distance(buf, p)) == word.size()) {
if (ec == std::errc() && ptr == buf + i) {
if (state.compiling()) {
state.dict.add(CoreWords::findi("_lit"));
state.dict.add(l);

@ -28,7 +28,7 @@ class Parser
public:
constexpr static int UnknownWord = -1;
int parse(State&, std::string_view&);
int parse(State&, const char *);
private:
int parseSource(State&);

@ -31,19 +31,26 @@ void State::compiling(bool yes)
dict.write(Dictionary::Compiling, yes);
}
void State::execute(Addr addr)
State::Error State::execute(Addr addr)
{
if (addr < CoreWords::WordCount) {
CoreWords::run(addr, *this);
} else {
pushr(0);
ip = addr - sizeof(Cell);
auto stat = setjmp(jmpbuf);
if (!stat) {
if (addr < CoreWords::WordCount) {
CoreWords::run(addr, *this);
} else {
pushr(0);
ip = addr - sizeof(Cell);
do {
ip += sizeof(Cell);
CoreWords::run(dict.read(ip), *this);
} while (ip);
do {
ip += sizeof(Cell);
CoreWords::run(dict.read(ip), *this);
} while (ip);
}
} else {
return static_cast<State::Error>(stat);
}
return State::Error::none;
}
std::size_t State::size() const noexcept

@ -22,6 +22,7 @@
#include "dictionary.hpp"
#include "types.hpp"
#include <csetjmp>
#include <cstddef>
constexpr unsigned DataStackSize = 8;
@ -29,6 +30,16 @@ constexpr unsigned ReturnStackSize = 8;
struct State
{
enum class Error : int {
none,
push,
pop,
pushr,
popr,
top,
pick
};
Addr ip = 0;
Dictionary& dict;
void (*input)(State&);
@ -38,26 +49,28 @@ struct State
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);
void execute(Addr);
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)
throw exc_push();
std::longjmp(jmpbuf, static_cast<int>(Error::push));
*++dsp = value;
}
inline Cell pop() {
if (dsp < dstack)
throw exc_pop();
std::longjmp(jmpbuf, static_cast<int>(Error::pop));
return *dsp--;
}
@ -68,34 +81,27 @@ struct State
inline void pushr(Cell value) {
if (rsp == rstack + ReturnStackSize - 1)
throw exc_pushr();
std::longjmp(jmpbuf, static_cast<int>(Error::pushr));
*++rsp = value;
}
inline Cell popr() {
if (rsp < rstack)
throw exc_popr();
std::longjmp(jmpbuf, static_cast<int>(Error::popr));
return *rsp--;
}
inline Cell& top() {
if (dsp < dstack)
throw exc_top();
std::longjmp(jmpbuf, static_cast<int>(Error::top));
return *dsp;
}
inline Cell& pick(std::size_t i) {
if (dsp - i < dstack)
throw exc_pick();
std::longjmp(jmpbuf, static_cast<int>(Error::pick));
return *(dsp - i);
}
struct exc_pop {};
struct exc_push {};
struct exc_popr {};
struct exc_pushr {};
struct exc_top {};
struct exc_pick {};
};
#endif // ALEEFORTH_STATE_HPP

Loading…
Cancel
Save