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.
alee-forth/parser.hpp

112 lines
3.8 KiB
C++

2 years ago
/**
* 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_PARSER_HPP
#define ALEEFORTH_PARSER_HPP
#include "executor.hpp"
class Parser
{
public:
ParseStatus parse(State& state, std::string_view& str) {
const auto end = str.find_first_of(" \t\n\r");
2 years ago
const auto sub = str.substr(0, end);
2 years ago
if (sub.empty())
return ParseStatus::Finished;
2 years ago
2 years ago
if (state.pass != Pass::None) {
switch (state.pass) {
case Pass::Comment:
2 years ago
if (str.front() == ')')
2 years ago
state.pass = Pass::None;
2 years ago
2 years ago
str = str.substr(1);
break;
case Pass::Colon:
state.pass = Pass::None;
state.compiling = true;
state.dict.addDefinition(sub);
break;
case Pass::Constant:
state.pass = Pass::None;
2 years ago
state.compiling = true;
2 years ago
state.dict.addDefinition(sub);
state.dict.add(CoreWords::HiddenWordLiteral);
state.dict.add(state.pop());
2 years ago
state.dict.add(CoreWords::findi(";"));
2 years ago
CoreWords::run(CoreWords::findi(";"), state);
2 years ago
break;
2 years ago
default:
break;
}
} else {
if (auto i = CoreWords::findi(sub); i >= 0) {
if (state.compiling)
2 years ago
state.dict.add(i);
2 years ago
if (!state.compiling || sub.front() == ';')
CoreWords::run(i, state);
} else if (auto j = state.dict.find(sub); j > 0) {
auto e = state.dict.getexec(j);
if (state.compiling) {
if (state.dict.read(j) & CoreWords::Immediate) {
state.compiling = false;
Executor::fullexec(state, e);
state.compiling = true;
} else {
state.dict.add(CoreWords::HiddenWordJump);
state.dict.add(e);
}
} else {
Executor::fullexec(state, e);
}
} else {
char *p;
const auto l = static_cast<Cell>(std::strtol(sub.data(), &p, 10));
2 years ago
2 years ago
if (p != sub.data()) {
if (state.compiling) {
state.dict.add(CoreWords::HiddenWordLiteral);
state.dict.add(l);
} else {
state.push(l);
}
} else {
return ParseStatus::Error;
}
}
2 years ago
2 years ago
if (end == std::string_view::npos)
2 years ago
return ParseStatus::Finished;
}
2 years ago
const auto next = str.find_first_not_of(" \t\n\r", end);
2 years ago
2 years ago
if (next == std::string_view::npos) {
2 years ago
return ParseStatus::Finished;
2 years ago
} else {
str = str.substr(next);
return ParseStatus::Continue;
}
2 years ago
}
};
#endif // ALEEFORTH_PARSER_HPP