You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
3.9 KiB
C++

/// sforth, an implementation of forth
/// Copyright (C) 2024 Clyne Sullivan <clyne@bitgloo.com>
///
/// This program is free software: you can redistribute it and/or modify it
/// under the terms of the GNU 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 General Public License for
/// more details.
///
/// You should have received a copy of the GNU General Public License along
/// with this program. If not, see <http://www.gnu.org/licenses/>.
#include "sforth/forth.hpp"
#include <array>
#include <charconv>
#include <fstream>
#include <iostream>
#include <span>
#include <string>
constinit static sforth::forth<8192> forth {sforth::initialize<&forth>()};
bool sforth_debug_hook()
{
char c;
std::cout << "DS: ";
for (auto it = forth.sp; it != forth.dstack.end(); it++) {
std::cout << *it << ' ';
}
std::cout << std::endl;
std::cout << "RS: ";
for (auto it = forth.rp; it != forth.rstack.end(); it++) {
if (auto w = forth.lookup(*it); w)
std::cout << (*w)->name() << '+' << ((sforth::addr)*it - std::bit_cast<sforth::addr>((*w)->body())) << ' ';
else
std::cout << *it << ' ';
}
std::cout << std::endl;
std::cout << "HERE: " << (sforth::addr)forth.here << std::endl;
std::cout << "IP: ";
if (auto w = forth.lookup(forth.ip); w)
std::cout << (*w)->name() << '+' << ((sforth::addr)forth.ip - std::bit_cast<sforth::addr>((*w)->body())) << ' ';
else
std::cout << forth.ip << ' ';
std::cout << std::endl << "> ";
std::cin >> c;
return true;
}
static bool parse_stream(auto&, std::istream&, bool say_okay = false);
constinit static sforth::native_word<".", [](auto) {
char buf[8 * sizeof(sforth::cell) + 1] = {};
std::to_chars(buf, buf + sizeof(buf), forth.pop(), forth.base);
std::cout << buf << ' ';
}> dot;
constinit static sforth::native_word<"U.", [](auto) {
char buf[8 * sizeof(sforth::cell) + 1] = {};
std::to_chars(buf, buf + sizeof(buf), std::bit_cast<sforth::addr>(forth.pop()), forth.base);
std::cout << buf << ' ';
}, &dot> udot;
constinit static sforth::native_word<"EMIT", [](auto) {
std::cout << static_cast<char>(forth.pop());
}, &udot> emit;
constinit static sforth::native_word<"INCLUDE", [](auto) {
const auto w = forth.parse();
std::string s {w.begin(), w.end()};
std::ifstream file {s};
parse_stream(forth, file);
}, &emit> incl;
int main(int argc, const char *argv[])
{
std::span args (argv + 1, argc - 1);
dot.next = std::exchange(forth.next, &incl);
for (auto arg : args) {
if (std::ifstream file {arg}; parse_stream(forth, file))
return 0;
}
parse_stream(forth, std::cin, true);
}
bool parse_stream(auto &fth, std::istream& str, bool say_okay)
{
std::string line;
while (str.good()) {
std::getline(str, line);
if (!line.empty()) {
if (sforth::isequal(line, "bye"))
return true;
if constexpr (sforth::enable_exceptions) {
try {
fth.parse_line(line);
} catch (sforth::error e) {
std::cerr << sforth::error_string(e) << " in " << line << std::endl;
continue;
}
} else {
if (auto e = fth.parse_line(line); e) {
std::cerr << sforth::error_string(*e) << " in " << line << std::endl;
continue;
}
}
}
if (say_okay)
std::cout << (fth.compiling ? "compiled" : "ok") << std::endl;
}
return false;
}