build core.fth into executable

llvm
Clyne 2 years ago
parent a529c15918
commit 685accbcba

3
.gitignore vendored

@ -1,5 +1,8 @@
.*
*.o
*.dat
alee
alee-msp430
alee-standalone
libalee.a
core.fth.h

@ -10,7 +10,8 @@ all: alee
msp430: CXX := msp430-elf32-g++
msp430: AR := msp430-elf32-ar
msp430: CXXFLAGS += -Os -mmcu=msp430g2553 -ffunction-sections -fdata-sections -DMEMDICTSIZE=200
msp430: CXXFLAGS += -Os -mmcu=msp430g2553 -ffunction-sections -fdata-sections
msp430: CXXFLAGS += -DMEMDICTSIZE=200
msp430: LDFLAGS += -L/opt/msp430-elf32/include -Wl,-gc-sections
msp430: alee-msp430
@ -20,13 +21,25 @@ small: alee
fast: CXXFLAGS += -O3 -march=native -mtune=native -flto
fast: alee
alee: $(LIBFILE)
standalone: core.fth.h alee-standalone
alee: $(LIBFILE)
alee-msp430: $(LIBFILE)
alee-standalone: $(LIBFILE)
$(LIBFILE): $(OBJFILES)
$(AR) cr $@ $(OBJFILES)
core.fth.h: alee.dat
xxd -i $< > $@
sed -i "s/unsigned /static const &/" $@
alee.dat: alee core.fth
echo "2 sys" | ./alee core.fth
clean:
rm -f alee alee-msp430 $(LIBFILE) $(OBJFILES)
rm -f alee alee-msp430 alee-standalone
rm -f $(LIBFILE) $(OBJFILES) alee.dat core.fth.h
.PHONY: all msp430 small fast standalone clean

@ -0,0 +1,176 @@
/**
* 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 "splitmemdict.hpp"
#include <charconv>
#include <fstream>
#include <iostream>
#include <vector>
#include "core.fth.h"
static bool okay = false;
static void readchar(State& state);
static void parseLine(Parser&, State&, const std::string&);
static void parseFile(Parser&, State&, std::istream&);
static Parser parser;
int main(int argc, char *argv[])
{
SplitMemDict<alee_dat_len> dict (alee_dat);
State state (dict, readchar);
std::vector args (argv + 1, argv + argc);
for (const auto& a : args) {
std::ifstream file (a);
parseFile(parser, state, file);
}
okay = true;
parseFile(parser, state, std::cin);
return 0;
}
static void readchar(State& state)
{
auto idx = state.dict.read(Dictionary::Input);
Addr addr = Dictionary::Input + sizeof(Cell) + idx;
auto c = std::cin.get();
if (isupper(c))
c += 32;
state.dict.writebyte(addr, c ? c : ' ');
}
static void save(State& state)
{
std::ofstream file ("alee.dat", std::ios::binary);
if (file.good()) {
for (Addr i = 0; i < state.dict.here(); ++i)
file.put(state.dict.readbyte(i));
}
}
static void load(State& state)
{
std::ifstream file ("alee.dat", std::ios::binary);
Addr i = 0;
while (file.good())
state.dict.writebyte(i++, file.get());
}
#include <cstring>
void user_sys(State& state)
{
char buf[32] = {0};
switch (state.pop()) {
case 0: // .
std::to_chars(buf, buf + sizeof(buf), state.pop(),
state.dict.read(Dictionary::Base));
std::cout << buf << ' ';
break;
case 1: // emit
std::cout << static_cast<char>(state.pop());
break;
case 2: // save
save(state);
break;
case 3: // load
load(state);
break;
case 4: // u.
{
Addr ucell = static_cast<Addr>(state.pop());
std::to_chars(buf, buf + sizeof(buf), ucell,
state.dict.read(Dictionary::Base));
std::cout << buf << ' ';
}
break;
case 5: // eval
{
auto oldip = state.ip;
std::jmp_buf oldjb;
memcpy(oldjb, state.jmpbuf, sizeof(std::jmp_buf));
state.ip = 0;
parser.parseSource(state);
memcpy(state.jmpbuf, oldjb, sizeof(std::jmp_buf));
state.ip = oldip;
}
break;
}
}
void parseLine(Parser& parser, State& state, const std::string& line)
{
if (auto r = parser.parse(state, line.c_str()); r == 0) {
if (okay)
std::cout << (state.compiling() ? "compiled" : "ok") << std::endl;
} else {
switch (r) {
case Parser::UnknownWord:
std::cout << "word not found in: " << line << std::endl;
break;
case static_cast<int>(State::Error::push):
std::cout << "stack overflow" << std::endl;
break;
case static_cast<int>(State::Error::pushr):
std::cout << "return stack overflow" << std::endl;
break;
case static_cast<int>(State::Error::popr):
std::cout << "return stack underflow" << std::endl;
break;
case static_cast<int>(State::Error::pop):
case static_cast<int>(State::Error::top):
case static_cast<int>(State::Error::pick):
std::cout << "stack underflow" << std::endl;
break;
default:
std::cout << "error: " << r << std::endl;
break;
}
while (state.size())
state.pop();
while (state.rsize())
state.popr();
state.dict.write(Dictionary::Compiling, 0);
state.ip = 0;
}
}
void parseFile(Parser& parser, State& state, std::istream& file)
{
while (file.good()) {
std::string line;
std::getline(file, line);
if (line == "bye")
exit(0);
parseLine(parser, state, line);
}
}

@ -0,0 +1,85 @@
/**
* 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/>.
*/
#ifndef ALEEFORTH_SPLITMEMDICT_HPP
#define ALEEFORTH_SPLITMEMDICT_HPP
#include "dictionary.hpp"
#include <cstring>
#ifndef MEMDICTSIZE
#define MEMDICTSIZE (65536)
#endif
constexpr unsigned long int MemDictSize = MEMDICTSIZE;
template<unsigned long int RON>
class SplitMemDict : public Dictionary
{
const uint8_t *rodict;
uint8_t rwdict[MemDictSize];
uint8_t extra[Dictionary::Begin];
public:
constexpr SplitMemDict(const uint8_t *rod):
rodict(rod)
{
std::memcpy(extra, rodict, sizeof(extra));
}
virtual Cell read(Addr addr) const noexcept final {
const uint8_t *dict;
if (addr < RON) {
dict = addr < Dictionary::Begin ? extra : rodict;
} else {
dict = rwdict;
addr -= RON;
}
return *reinterpret_cast<const Cell *>(dict + addr);
}
virtual void write(Addr addr, Cell value) noexcept final {
if (addr >= RON)
*reinterpret_cast<Cell *>(rwdict + addr - RON) = value;
else if (addr < Dictionary::Begin)
*reinterpret_cast<Cell *>(extra + addr) = value;
}
virtual uint8_t readbyte(Addr addr) const noexcept final {
const uint8_t *dict;
if (addr < RON) {
dict = addr < Dictionary::Begin ? extra : rodict;
} else {
dict = rwdict;
addr -= RON;
}
return dict[addr];
}
virtual void writebyte(Addr addr, uint8_t value) noexcept final {
if (addr >= RON)
rwdict[addr - RON] = value;
else if (addr < Dictionary::Begin)
extra[addr] = value;
}
};
#endif // ALEEFORTH_SPLITMEMDICT_HPP
Loading…
Cancel
Save