]> code.bitgloo.com Git - bitgloo/alee-forth.git/commitdiff
compact implementation; runs on msp430
authorClyne Sullivan <clyne@bitgloo.com>
Sat, 25 Feb 2023 00:09:53 +0000 (19:09 -0500)
committerClyne Sullivan <clyne@bitgloo.com>
Sat, 25 Feb 2023 00:09:53 +0000 (19:09 -0500)
13 files changed:
.gitignore
Makefile
alee-msp430.cpp [new file with mode: 0644]
alee.cpp
corewords.cpp
corewords.hpp
dictionary.cpp
dictionary.hpp
memdict.hpp
parser.cpp
parser.hpp
state.cpp
state.hpp

index fb13a21dbd05ca7a632c9422ffaa729505f41902..a877dd4c3b4ea2231f49e1340de6fb75b869e87c 100644 (file)
@@ -1,4 +1,5 @@
 .*
 *.o
 alee
+alee-msp430
 libalee.a
index 65dc7912d04b4b3af7317399b14f3ca15eb62844..45011b6894d90e32bd0ee639bbded33df0da973a 100644 (file)
--- 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 (file)
index 0000000..00151f0
--- /dev/null
@@ -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;
+    }
+}
+
index 41610e4ec83a1649bd76c9e58ba39a182e3f1cc0..0f270a83efdc892e41066571eb2c8b1645584df1 100644 (file)
--- 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;
         }
     }
index 2d981170dd6dac966e33ca4104c83584e9675b68..c0cec485bdde43afab1b357681d229cc4832b9af 100644 (file)
@@ -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;
index 6f982a0be296974e7ff5fba86db644eb786d4f19..ab34c78d126b15b966ceec264c20ed1656159351 100644 (file)
@@ -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&);
 
index cf04cb4e953ffd35c7b7a1531d5e456a4fe417fa..cb2aba8523d0ad53ab98bbd2f08a72788b84a1a7 100644 (file)
 #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;
index fa081cb2ff5d11c63300686b897c9a61261676ea..9987e8f08af1f04d8f8ae88e9fe4f983ccab424e 100644 (file)
@@ -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
index b956d5da286a547d494ddf2890752ddab52c5e81..65063e02092c097b265b21a0e7714bb7b3f63cc5 100644 (file)
 
 #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;
     }
 };
index 01dbb9048c10ea5afd86bcf23a6f4d08debbed03..af5da6969d552411d4185339b9457f5cd1b80bad 100644 (file)
 #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);
index 8a322e27d5aa2a9c1af8c44729c3784897853f30..5bcf3f95bc607058396d92a37620b70457e516e1 100644 (file)
@@ -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&);
index c3711016cc867b92528f8248a2db183ed856e5d1..1510352e000fd86be625bcbb9b76b90505882f4a 100644 (file)
--- 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
index 279aefd2f57317d95cdbde8873f253f84779dbbc..22f0d74da1a5ea3ec6fa312dbde3352701e47ce0 100644 (file)
--- 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