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 *.o
alee alee
alee-msp430
libalee.a libalee.a

@ -1,24 +1,32 @@
CXXFLAGS += -std=c++17 -g3 -ggdb -O0 \ 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 CXXFILES := corewords.cpp dictionary.cpp parser.cpp state.cpp
OBJFILES := $(subst .cpp,.o,$(CXXFILES)) OBJFILES := $(subst .cpp,.o,$(CXXFILES))
LIBFILE := libalee.a 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: CXXFLAGS += -Os
small: $(EXEFILE) small: alee
fast: CXXFLAGS += -O3 -march=native -mtune=native fast: CXXFLAGS += -O3 -march=native -mtune=native
fast: $(EXEFILE) fast: alee
alee: $(LIBFILE)
$(EXEFILE): $(LIBFILE) alee-msp430: $(LIBFILE)
$(LIBFILE): $(OBJFILES) $(LIBFILE): $(OBJFILES)
$(AR) cr $@ $(OBJFILES) $(AR) cr $@ $(OBJFILES)
clean: 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 bool okay = false;
static void readchar(State& state); 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&); static void parseFile(Parser&, State&, std::istream&);
int main(int argc, char *argv[]) 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) if (okay)
std::cout << (state.compiling() ? "compiled" : "ok") << std::endl; std::cout << (state.compiling() ? "compiled" : "ok") << std::endl;
} else { } else {
@ -116,6 +116,7 @@ void parseLine(Parser& parser, State& state, std::string_view line)
std::cout << "word not found in: " << line << std::endl; std::cout << "word not found in: " << line << std::endl;
break; break;
default: default:
std::cout << "error: " << r << std::endl;
break; break;
} }
} }

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

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

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

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

@ -21,26 +21,29 @@
#include "dictionary.hpp" #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 class MemDict : public Dictionary
{ {
uint8_t dict[MemDictSize]; uint8_t dict[MemDictSize];
public: public:
virtual Cell read(Addr addr) const final { virtual Cell read(Addr addr) const noexcept final {
return *reinterpret_cast<const Cell *>(dict + addr); 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; *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]; 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; dict[addr] = value;
} }
}; };

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

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

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

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

Loading…
Cancel
Save