aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClyne Sullivan <clyne@bitgloo.com>2023-02-24 19:09:53 -0500
committerClyne Sullivan <clyne@bitgloo.com>2023-02-24 19:09:53 -0500
commit0b88b4596e6265863e75e7aabcca52734e147fae (patch)
tree2210e75d0b5eff6e462770e5278a1baf504423b0
parent914a75b2097090595d12015b750f97dc55bf7dcd (diff)
compact implementation; runs on msp430
-rw-r--r--.gitignore1
-rw-r--r--Makefile22
-rw-r--r--alee-msp430.cpp162
-rw-r--r--alee.cpp7
-rw-r--r--corewords.cpp30
-rw-r--r--corewords.hpp4
-rw-r--r--dictionary.cpp25
-rw-r--r--dictionary.hpp31
-rw-r--r--memdict.hpp13
-rw-r--r--parser.cpp27
-rw-r--r--parser.hpp2
-rw-r--r--state.cpp27
-rw-r--r--state.hpp34
13 files changed, 289 insertions, 96 deletions
diff --git a/.gitignore b/.gitignore
index fb13a21..a877dd4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.*
*.o
alee
+alee-msp430
libalee.a
diff --git a/Makefile b/Makefile
index 65dc791..45011b6 100644
--- a/Makefile
+++ b/Makefile
@@ -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)
diff --git a/alee-msp430.cpp b/alee-msp430.cpp
new file mode 100644
index 0000000..00151f0
--- /dev/null
+++ b/alee-msp430.cpp
@@ -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;
+ }
+}
+
diff --git a/alee.cpp b/alee.cpp
index 41610e4..0f270a8 100644
--- a/alee.cpp
+++ b/alee.cpp
@@ -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;
}
}
diff --git a/corewords.cpp b/corewords.cpp
index 2d98117..c0cec48 100644
--- a/corewords.cpp
+++ b/corewords.cpp
@@ -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;
diff --git a/corewords.hpp b/corewords.hpp
index 6f982a0..ab34c78 100644
--- a/corewords.hpp
+++ b/corewords.hpp
@@ -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&);
diff --git a/dictionary.cpp b/dictionary.cpp
index cf04cb4..cb2aba8 100644
--- a/dictionary.cpp
+++ b/dictionary.cpp
@@ -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;
diff --git a/dictionary.hpp b/dictionary.hpp
index fa081cb..9987e8f 100644
--- a/dictionary.hpp
+++ b/dictionary.hpp
@@ -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
diff --git a/memdict.hpp b/memdict.hpp
index b956d5d..65063e0 100644
--- a/memdict.hpp
+++ b/memdict.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;
}
};
diff --git a/parser.cpp b/parser.cpp
index 01dbb90..af5da69 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -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);
diff --git a/parser.hpp b/parser.hpp
index 8a322e2..5bcf3f9 100644
--- a/parser.hpp
+++ b/parser.hpp
@@ -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&);
diff --git a/state.cpp b/state.cpp
index c371101..1510352 100644
--- a/state.cpp
+++ b/state.cpp
@@ -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
diff --git a/state.hpp b/state.hpp
index 279aefd..22f0d74 100644
--- a/state.hpp
+++ b/state.hpp
@@ -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