Completed parser refactoring
dc / build (push) Has been cancelled
Details
dc / build (push) Has been cancelled
Details
This commit is contained in:
parent
d0ffb8610a
commit
f349442410
|
@ -1,108 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="CMakePresetLoader">{
|
||||
"useNewFormat": true
|
||||
}</component>
|
||||
<component name="CMakeReloadState">
|
||||
<option name="reloaded" value="true" />
|
||||
</component>
|
||||
<component name="CMakeRunConfigurationManager">
|
||||
<generated>
|
||||
<config projectName="dc" targetName="dc" />
|
||||
<config projectName="dc" targetName="src" />
|
||||
</generated>
|
||||
</component>
|
||||
<component name="CMakeSettings">
|
||||
<configurations>
|
||||
<configuration PROFILE_NAME="Debug" ENABLED="true" CONFIG_NAME="Debug" />
|
||||
</configurations>
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="f3f56053-2bfb-4446-a04f-3b5d77ba6109" name="Changes" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/src/macro.h" beforeDir="false" afterPath="$PROJECT_DIR$/src/macro.h" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="ClangdSettings">
|
||||
<option name="formatViaClangd" value="false" />
|
||||
</component>
|
||||
<component name="ExecutionTargetManager" SELECTED_TARGET="CMakeBuildProfile:Debug" />
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="MarkdownSettingsMigration">
|
||||
<option name="stateVersion" value="1" />
|
||||
</component>
|
||||
<component name="ProjectApplicationVersion">
|
||||
<option name="ide" value="CLion" />
|
||||
<option name="majorVersion" value="2023" />
|
||||
<option name="minorVersion" value="3.4" />
|
||||
</component>
|
||||
<component name="ProjectColorInfo">{
|
||||
"customColor": "",
|
||||
"associatedIndex": 3
|
||||
}</component>
|
||||
<component name="ProjectId" id="2dOfSS6eyrQnil4C27nbLcbbn3t" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"ASKED_ADD_EXTERNAL_FILES": "true",
|
||||
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.cidr.known.project.marker": "true",
|
||||
"RunOnceActivity.readMode.enableVisualFormatting": "true",
|
||||
"cf.first.check.clang-format": "false",
|
||||
"cidr.known.project.marker": "true",
|
||||
"git-widget-placeholder": "factory__parsing",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}]]></component>
|
||||
<component name="RunManager" selected="CMake Application.dc">
|
||||
<configuration name="dc" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="dc" TARGET_NAME="dc" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="dc" RUN_TARGET_NAME="dc">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="src" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="dc" TARGET_NAME="src" CONFIG_NAME="Debug">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<list>
|
||||
<item itemvalue="CMake Application.dc" />
|
||||
<item itemvalue="CMake Application.src" />
|
||||
</list>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="f3f56053-2bfb-4446-a04f-3b5d77ba6109" name="Changes" comment="" />
|
||||
<created>1709884046913</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1709884046913</updated>
|
||||
<workItem from="1709884048698" duration="104000" />
|
||||
<workItem from="1709885930599" duration="333000" />
|
||||
<workItem from="1709888996789" duration="7855000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
</project>
|
399
src/eval.cpp
399
src/eval.cpp
|
@ -6,8 +6,6 @@
|
|||
#include "macro.h"
|
||||
#include "is_num.h"
|
||||
|
||||
// TODO: replace 'val' with 'token'
|
||||
|
||||
#define MACRO_COND(VAL) ((VAL.length() == 1 && VAL == "["))
|
||||
#define MACRO_CMD_COND(VAL) ((VAL.length() == 2 || VAL.length() == 3) && \
|
||||
(VAL.at(0) == '>' || VAL.at(0) == '<' || \
|
||||
|
@ -19,286 +17,69 @@
|
|||
(VAL.at(0) == ':' || VAL.at(0) == ';'))
|
||||
|
||||
#define X_CONTAINS_Y(X, Y) ((Y.find_first_of(X) != std::string::npos))
|
||||
#define MAKE_UNIQUE_PTR(CLASS, ARG) [](){ return std::make_unique<CLASS>(ARG); }
|
||||
|
||||
void Evaluate::init_op_factory() {
|
||||
void Evaluate::init_environment() {
|
||||
// Numerical operations
|
||||
this->op_factory.emplace("+", [](){ return std::make_unique<Math>(OPType::ADD); });
|
||||
this->op_factory.emplace("-", [](){ return std::make_unique<Math>(OPType::SUB); });
|
||||
this->op_factory.emplace("*", [](){ return std::make_unique<Math>(OPType::MUL); });
|
||||
this->op_factory.emplace("/", [](){ return std::make_unique<Math>(OPType::DIV); });
|
||||
this->op_factory.emplace("%", [](){ return std::make_unique<Math>(OPType::MOD); });
|
||||
this->op_factory.emplace("~", [](){ return std::make_unique<Math>(OPType::DIV_MOD); });
|
||||
this->op_factory.emplace("|", [](){ return std::make_unique<Math>(OPType::MOD_EXP); });
|
||||
this->op_factory.emplace("^", [](){ return std::make_unique<Math>(OPType::EXP); });
|
||||
this->op_factory.emplace("v", [](){ return std::make_unique<Math>(OPType::SQRT); });
|
||||
this->op_factory.emplace("sin", [](){ return std::make_unique<Math>(OPType::SIN); });
|
||||
this->op_factory.emplace("cos", [](){ return std::make_unique<Math>(OPType::COS); });
|
||||
this->op_factory.emplace("tan", [](){ return std::make_unique<Math>(OPType::TAN); });
|
||||
this->op_factory.emplace("asin", [](){ return std::make_unique<Math>(OPType::ASIN); });
|
||||
this->op_factory.emplace("acos", [](){ return std::make_unique<Math>(OPType::ACOS); });
|
||||
this->op_factory.emplace("atan", [](){ return std::make_unique<Math>(OPType::ATAN); });
|
||||
this->op_factory.emplace("!", [](){ return std::make_unique<Math>(OPType::FACT); });
|
||||
this->op_factory.emplace("pi", [](){ return std::make_unique<Math>(OPType::PI); });
|
||||
this->op_factory.emplace("e", [](){ return std::make_unique<Math>(OPType::E); });
|
||||
this->op_factory.emplace("+", MAKE_UNIQUE_PTR(Math, OPType::ADD));
|
||||
this->op_factory.emplace("-", MAKE_UNIQUE_PTR(Math, OPType::SUB));
|
||||
this->op_factory.emplace("*", MAKE_UNIQUE_PTR(Math, OPType::MUL));
|
||||
this->op_factory.emplace("/", MAKE_UNIQUE_PTR(Math, OPType::DIV));
|
||||
this->op_factory.emplace("%", MAKE_UNIQUE_PTR(Math, OPType::MOD));
|
||||
this->op_factory.emplace("~", MAKE_UNIQUE_PTR(Math, OPType::DIV_MOD));
|
||||
this->op_factory.emplace("|", MAKE_UNIQUE_PTR(Math, OPType::MOD_EXP));
|
||||
this->op_factory.emplace("^", MAKE_UNIQUE_PTR(Math, OPType::EXP));
|
||||
this->op_factory.emplace("v", MAKE_UNIQUE_PTR(Math, OPType::SQRT));
|
||||
this->op_factory.emplace("sin", MAKE_UNIQUE_PTR(Math, OPType::SIN));
|
||||
this->op_factory.emplace("cos", MAKE_UNIQUE_PTR(Math, OPType::COS));
|
||||
this->op_factory.emplace("tan", MAKE_UNIQUE_PTR(Math, OPType::TAN));
|
||||
this->op_factory.emplace("asin", MAKE_UNIQUE_PTR(Math, OPType::ASIN));
|
||||
this->op_factory.emplace("acos", MAKE_UNIQUE_PTR(Math, OPType::ACOS));
|
||||
this->op_factory.emplace("atan", MAKE_UNIQUE_PTR(Math, OPType::ATAN));
|
||||
this->op_factory.emplace("!", MAKE_UNIQUE_PTR(Math, OPType::FACT));
|
||||
this->op_factory.emplace("pi", MAKE_UNIQUE_PTR(Math, OPType::PI));
|
||||
this->op_factory.emplace("e", MAKE_UNIQUE_PTR(Math, OPType::E));
|
||||
// Stack operations
|
||||
this->op_factory.emplace("p", []() { return std::make_unique<Stack>(OPType::PCG); });
|
||||
this->op_factory.emplace("pb", []() { return std::make_unique<Stack>(OPType::PBB); });
|
||||
this->op_factory.emplace("ph", []() { return std::make_unique<Stack>(OPType::PBH); });
|
||||
this->op_factory.emplace("po", []() { return std::make_unique<Stack>(OPType::PBO); });
|
||||
this->op_factory.emplace("P", []() { return std::make_unique<Stack>(OPType::P); });
|
||||
this->op_factory.emplace("c", []() { return std::make_unique<Stack>(OPType::CLR); });
|
||||
this->op_factory.emplace("R", []() { return std::make_unique<Stack>(OPType::PH); });
|
||||
this->op_factory.emplace("r", []() { return std::make_unique<Stack>(OPType::SO); });
|
||||
this->op_factory.emplace("d", []() { return std::make_unique<Stack>(OPType::DP); });
|
||||
this->op_factory.emplace("f", []() { return std::make_unique<Stack>(OPType::PS); });
|
||||
this->op_factory.emplace("Z", []() { return std::make_unique<Stack>(OPType::CH); });
|
||||
this->op_factory.emplace("z", []() { return std::make_unique<Stack>(OPType::CS); });
|
||||
this->op_factory.emplace("p", MAKE_UNIQUE_PTR(Stack, OPType::PCG));
|
||||
this->op_factory.emplace("pb", MAKE_UNIQUE_PTR(Stack, OPType::PBB));
|
||||
this->op_factory.emplace("ph", MAKE_UNIQUE_PTR(Stack, OPType::PBH));
|
||||
this->op_factory.emplace("po", MAKE_UNIQUE_PTR(Stack, OPType::PBO));
|
||||
this->op_factory.emplace("P", MAKE_UNIQUE_PTR(Stack, OPType::P));
|
||||
this->op_factory.emplace("c", MAKE_UNIQUE_PTR(Stack, OPType::CLR));
|
||||
this->op_factory.emplace("R", MAKE_UNIQUE_PTR(Stack, OPType::PH));
|
||||
this->op_factory.emplace("r", MAKE_UNIQUE_PTR(Stack, OPType::SO));
|
||||
this->op_factory.emplace("d", MAKE_UNIQUE_PTR(Stack, OPType::DP));
|
||||
this->op_factory.emplace("f", MAKE_UNIQUE_PTR(Stack, OPType::PS));
|
||||
this->op_factory.emplace("Z", MAKE_UNIQUE_PTR(Stack, OPType::CH));
|
||||
this->op_factory.emplace("z", MAKE_UNIQUE_PTR(Stack, OPType::CS));
|
||||
this->op_factory.emplace("k", MAKE_UNIQUE_PTR(Stack, OPType::SP));
|
||||
this->op_factory.emplace("K", MAKE_UNIQUE_PTR(Stack, OPType::GP));
|
||||
this->op_factory.emplace("o", MAKE_UNIQUE_PTR(Stack, OPType::SOR));
|
||||
this->op_factory.emplace("O", MAKE_UNIQUE_PTR(Stack, OPType::GOR));
|
||||
this->op_factory.emplace("i", MAKE_UNIQUE_PTR(Stack, OPType::SIR));
|
||||
this->op_factory.emplace("I", MAKE_UNIQUE_PTR(Stack, OPType::GIR));
|
||||
// Macro operations
|
||||
this->op_factory.emplace("x", MAKE_UNIQUE_PTR(Macro, OPType::EX));
|
||||
this->op_factory.emplace("?", MAKE_UNIQUE_PTR(Macro, OPType::RI));
|
||||
}
|
||||
|
||||
std::optional<std::string> Evaluate::eval() {
|
||||
// Set up environment
|
||||
init_environment();
|
||||
|
||||
for(size_t idx = 0; idx < this->expr.size(); idx++) {
|
||||
auto val = this->expr.at(idx);
|
||||
std::optional<std::string> err;
|
||||
|
||||
//
|
||||
// NUMERICAL OPERATIONS
|
||||
//
|
||||
if(val == "+") {
|
||||
std::unique_ptr<IOperation> math = std::make_unique<Math>(OPType::ADD);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
auto token = this->expr.at(idx);
|
||||
|
||||
// If token exists in the environment, instantiate it through the factory
|
||||
if (this->op_factory.find(token) != this->op_factory.end()) {
|
||||
std::unique_ptr<IOperation> operation = this->op_factory[token]();
|
||||
err = operation->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "-") {
|
||||
auto math = std::make_unique<Math>(OPType::SUB);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "*") {
|
||||
auto math = std::make_unique<Math>(OPType::MUL);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "/") {
|
||||
auto math = std::make_unique<Math>(OPType::DIV);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "%") {
|
||||
auto math = std::make_unique<Math>(OPType::MOD);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "~") {
|
||||
auto math = std::make_unique<Math>(OPType::DIV_MOD);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "|") {
|
||||
auto math = std::make_unique<Math>(OPType::MOD_EXP);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "^") {
|
||||
auto math = std::make_unique<Math>(OPType::EXP);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "v") {
|
||||
auto math = std::make_unique<Math>(OPType::SQRT);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "sin") {
|
||||
auto math = std::make_unique<Math>(OPType::SIN);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "cos") {
|
||||
auto math = std::make_unique<Math>(OPType::COS);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "tan") {
|
||||
auto math = std::make_unique<Math>(OPType::TAN);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "asin") {
|
||||
auto math = std::make_unique<Math>(OPType::ASIN);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "acos") {
|
||||
auto math = std::make_unique<Math>(OPType::ACOS);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "atan") {
|
||||
auto math = std::make_unique<Math>(OPType::ATAN);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "!") {
|
||||
auto math = std::make_unique<Math>(OPType::FACT);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "pi") {
|
||||
auto math = std::make_unique<Math>(OPType::PI);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "e") {
|
||||
auto math = std::make_unique<Math>(OPType::E);
|
||||
err = math->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
//
|
||||
// STACK OPERATIONS
|
||||
//
|
||||
else if(val == "p") { // PRINT TOP ELEMENT OF STACK
|
||||
auto op = std::make_unique<Stack>(OPType::PCG);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "pb") { // PRINT TOP ELEMENT IN BASE 2
|
||||
auto op = std::make_unique<Stack>(OPType::PBB);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "ph") { // PRINT TOP ELEMENT IN BASE 16
|
||||
auto op = std::make_unique<Stack>(OPType::PBH);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "po") { // PRINT TOP ELEMENT IN BASE 8
|
||||
auto op = std::make_unique<Stack>(OPType::PBO);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "P") { // PRINT TOP ELEMENT WITHOUT NEWLINE
|
||||
auto op = std::make_unique<Stack>(OPType::P);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "c") { // CLEAR THE STACK
|
||||
auto op = std::make_unique<Stack>(OPType::CLR);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "R") { // POP HEAD OF THE STACK WITHOUT PRINTING IT
|
||||
auto op = std::make_unique<Stack>(OPType::PH);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "r") { // SWAP ORDER OF THE TWO TOP ELEMENTS
|
||||
auto op = std::make_unique<Stack>(OPType::SO);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "d") { // DUPLICATE THE HEAD OF THE STACK
|
||||
auto op = std::make_unique<Stack>(OPType::DP);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "f") { // PRINT THE WHOLE STACK
|
||||
auto op = std::make_unique<Stack>(OPType::PS);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "Z") { // COMPUTE HEAD SIZE(NUM. OF CHARS/DIGITS)
|
||||
auto op = std::make_unique<Stack>(OPType::CH);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "z") { // COMPUTE STACK SIZE
|
||||
auto op = std::make_unique<Stack>(OPType::CS);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "k") { // SET PRECISION
|
||||
auto op = std::make_unique<Stack>(OPType::SP);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "K") { // GET PRECISION
|
||||
auto op = std::make_unique<Stack>(OPType::GP);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "o") { // SET OUTPUT BASE
|
||||
auto op = std::make_unique<Stack>(OPType::SOR);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "O") { // GET OUTPUT BASE
|
||||
auto op = std::make_unique<Stack>(OPType::GOR);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "i") { // SET INPUT BASE
|
||||
auto op = std::make_unique<Stack>(OPType::SIR);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "I") { // GET INPUT BASE
|
||||
auto op = std::make_unique<Stack>(OPType::GIR);
|
||||
err = op->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "x") { // EXECUTE MACRO
|
||||
auto macro = std::make_unique<Macro>(OPType::EX);
|
||||
err = macro->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "?") { // READ LINE FROM STDIN
|
||||
auto macro = std::make_unique<Macro>(OPType::RI);
|
||||
err = macro->exec(this->stack, this->parameters, this->regs);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
} else if(val == "q") { // QUIT GRACEFULLY
|
||||
std::exit(0);
|
||||
} else {
|
||||
err = handle_special(val, idx);
|
||||
err = handle_special(token, idx);
|
||||
if(err != std::nullopt) {
|
||||
return err;
|
||||
}
|
||||
|
@ -308,21 +89,23 @@ std::optional<std::string> Evaluate::eval() {
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Evaluate::handle_special(std::string val, size_t &idx) {
|
||||
std::optional<std::string> Evaluate::handle_special(std::string token, size_t &idx) {
|
||||
std::optional<std::string> err = std::nullopt;
|
||||
|
||||
if(MACRO_COND(val)) {
|
||||
if(MACRO_COND(token)) {
|
||||
err = parse_macro(idx);
|
||||
} else if(MACRO_CMD_COND(val)) {
|
||||
err = parse_macro_command(val);
|
||||
} else if(REGISTER_COND(val)) {
|
||||
err = parse_register_command(val);
|
||||
} else if(ARRAY_COND(val)) {
|
||||
err = parse_array_command(val);
|
||||
} else if(MACRO_CMD_COND(token)) {
|
||||
err = parse_macro_command(token);
|
||||
} else if(REGISTER_COND(token)) {
|
||||
err = parse_register_command(token);
|
||||
} else if(ARRAY_COND(token)) {
|
||||
err = parse_array_command(token);
|
||||
} else if(this->parameters.iradix != 10) {
|
||||
err = parse_base_n(val);
|
||||
} else if(is_num<double>(val)) {
|
||||
this->stack.push_back(val);
|
||||
err = parse_base_n(token);
|
||||
} else if(is_num<double>(token)) {
|
||||
this->stack.push_back(token);
|
||||
} else if(token == "q") {
|
||||
std::exit(0);
|
||||
} else {
|
||||
return "Unrecognized option";
|
||||
}
|
||||
|
@ -330,15 +113,15 @@ std::optional<std::string> Evaluate::handle_special(std::string val, size_t &idx
|
|||
return err;
|
||||
}
|
||||
|
||||
std::optional<std::string> Evaluate::parse_base_n(const std::string& val) {
|
||||
std::optional<std::string> Evaluate::parse_base_n(const std::string& token) {
|
||||
// Discard values that are neither integers neither within "ABCDEF"
|
||||
if(!is_num<long>(val) && !X_CONTAINS_Y("ABCDEF", val)) {
|
||||
if(!is_num<long>(token) && !X_CONTAINS_Y("ABCDEF", token)) {
|
||||
return "This input base supports integers only";
|
||||
}
|
||||
|
||||
// Try to convert the number to the selected numeric base
|
||||
try {
|
||||
long number = std::stol(val, nullptr, this->parameters.iradix);
|
||||
long number = std::stol(token, nullptr, this->parameters.iradix);
|
||||
this->stack.push_back(std::to_string(number));
|
||||
} catch(...) {
|
||||
return "Invalid number for input base '"
|
||||
|
@ -393,7 +176,7 @@ std::optional<std::string> Evaluate::parse_macro(size_t &idx) {
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Evaluate::parse_macro_command(std::string val) {
|
||||
std::optional<std::string> Evaluate::parse_macro_command(std::string token) {
|
||||
// A macro command is a comparison symbol(>, <, =, >=, <=, !=)
|
||||
// followed by a register name(e.g, >A)
|
||||
// If command has length equal to three, then it's either '<=', '>=' or '!='
|
||||
|
@ -401,12 +184,12 @@ std::optional<std::string> Evaluate::parse_macro_command(std::string val) {
|
|||
// Check if command is >=, <= or !=
|
||||
std::string operation;
|
||||
char dc_register = 0;
|
||||
if(val.length() == 3) {
|
||||
operation = val.substr(0, 2);
|
||||
dc_register = val.at(2);
|
||||
if(token.length() == 3) {
|
||||
operation = token.substr(0, 2);
|
||||
dc_register = token.at(2);
|
||||
} else { // Otherwise it's either >, < or =
|
||||
operation = val.at(0);
|
||||
dc_register = val.at(1);
|
||||
operation = token.at(0);
|
||||
dc_register = token.at(1);
|
||||
}
|
||||
|
||||
// Macro commands works as follows
|
||||
|
@ -455,11 +238,11 @@ std::optional<std::string> Evaluate::parse_macro_command(std::string val) {
|
|||
return err;
|
||||
}
|
||||
|
||||
std::optional<std::string> Evaluate::parse_register_command(std::string val) {
|
||||
std::optional<std::string> Evaluate::parse_register_command(std::string token) {
|
||||
// A register command has length equal to 2
|
||||
// and starts either with 's', 'l'(i.e. "sX" or "lX")
|
||||
// or with 'S' or 'L'(i.e., "SX", "LX")
|
||||
if(val.at(0) == 's') {
|
||||
if(token.at(0) == 's') {
|
||||
// Check if main stack is empty
|
||||
if(this->stack.empty()) {
|
||||
return "This operation does not work on empty stack";
|
||||
|
@ -467,7 +250,7 @@ std::optional<std::string> Evaluate::parse_register_command(std::string val) {
|
|||
|
||||
// Otherwise pop an element from main stack and store it into
|
||||
// the register's top-of-the-stack. Any previous value gets overwritten
|
||||
auto reg_name = val.at(1);
|
||||
auto reg_name = token.at(1);
|
||||
auto head = this->stack.back();
|
||||
this->stack.pop_back();
|
||||
|
||||
|
@ -483,7 +266,7 @@ std::optional<std::string> Evaluate::parse_register_command(std::string val) {
|
|||
|
||||
// Populate register's 'reg_name' stack with top of main stack
|
||||
this->regs[reg_name].stack.push_back(head);
|
||||
} else if(val.at(0) == 'S') {
|
||||
} else if(token.at(0) == 'S') {
|
||||
// An uppercase 'S' pops the top of the main stack and
|
||||
// pushes it onto the stack of selected register.
|
||||
// The previous value of the register's stack becomes
|
||||
|
@ -494,7 +277,7 @@ std::optional<std::string> Evaluate::parse_register_command(std::string val) {
|
|||
return "This operation does not work on empty stack";
|
||||
}
|
||||
|
||||
auto reg_name = val.at(1);
|
||||
auto reg_name = token.at(1);
|
||||
auto head = this->stack.back();
|
||||
this->stack.pop_back();
|
||||
|
||||
|
@ -509,11 +292,11 @@ std::optional<std::string> Evaluate::parse_register_command(std::string val) {
|
|||
std::unordered_map<int, std::string>()
|
||||
};
|
||||
}
|
||||
} else if(val.at(0) == 'L') {
|
||||
} else if(token.at(0) == 'L') {
|
||||
// An uppercase 'L' pops the top of the register's stack
|
||||
// abd pushes it onto the main stack. The previous register's stack
|
||||
// value, if any, is accessible via the lowercase 'l' command
|
||||
auto reg_name = val.at(1);
|
||||
auto reg_name = token.at(1);
|
||||
|
||||
// Check if register exists
|
||||
if(this->regs.find(reg_name) == this->regs.end()) {
|
||||
|
@ -526,14 +309,14 @@ std::optional<std::string> Evaluate::parse_register_command(std::string val) {
|
|||
}
|
||||
|
||||
// Otherwise, pop an element from the register's stack and push it onto the main stack
|
||||
auto value = this->regs[reg_name].stack.back();
|
||||
auto ue = this->regs[reg_name].stack.back();
|
||||
this->regs[reg_name].stack.pop_back();
|
||||
this->stack.push_back(value);
|
||||
this->stack.push_back(ue);
|
||||
} else {
|
||||
// Otherwise retrieve the register name and push its value
|
||||
// to the stack without altering the register's stack.
|
||||
// If the register is empty, push '0' to the stack
|
||||
auto reg_name = val.at(1);
|
||||
auto reg_name = token.at(1);
|
||||
|
||||
// If register does not exist or its stack is empty, push '0' onto the main stack
|
||||
auto it = this->regs.find(reg_name);
|
||||
|
@ -543,21 +326,21 @@ std::optional<std::string> Evaluate::parse_register_command(std::string val) {
|
|||
}
|
||||
|
||||
// Otherwise, peek an element from the register's stack and push it onto the main stack
|
||||
auto value = this->regs[reg_name].stack.back();
|
||||
this->stack.push_back(value);
|
||||
auto ue = this->regs[reg_name].stack.back();
|
||||
this->stack.push_back(ue);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Evaluate::parse_array_command(std::string val) {
|
||||
std::optional<std::string> Evaluate::parse_array_command(std::string token) {
|
||||
// An array command has length equal to 2, starts
|
||||
// with either ':'(store) or ';'(read) and ends with
|
||||
// the register name(i.e., ':X' or ';X')
|
||||
if(val.at(0) == ':') {
|
||||
// An ':' command pops two values from the main stack. The second-to-top
|
||||
if(token.at(0) == ':') {
|
||||
// An ':' command pops two ues from the main stack. The second-to-top
|
||||
// element will be stored in the array indexed by the top-of-stack.
|
||||
auto reg_name = val.at(1);
|
||||
auto reg_name = token.at(1);
|
||||
|
||||
// Check if the main stack has enough elements
|
||||
if(this->stack.size() < 2) {
|
||||
|
@ -582,7 +365,7 @@ std::optional<std::string> Evaluate::parse_array_command(std::string val) {
|
|||
// If array does not exist, allocate a new array first
|
||||
auto it = this->regs.find(reg_name);
|
||||
if(it != this->regs.end()) { // Register exists
|
||||
// Always discard previous values of array
|
||||
// Always discard previous ues of array
|
||||
it->second.array.erase(idx);
|
||||
it->second.array.insert(std::pair<int, std::string>(idx, arr_val));
|
||||
} else { // Register doesn't exist
|
||||
|
@ -594,7 +377,7 @@ std::optional<std::string> Evaluate::parse_array_command(std::string val) {
|
|||
} else {
|
||||
// An ';' command pops top-of-stack abd uses it as an index
|
||||
// for the array. The selected value, if any, is pushed onto the stack
|
||||
auto reg_name = val.at(1);
|
||||
auto reg_name = token.at(1);
|
||||
|
||||
// Check if the main stack is empty
|
||||
if(this->stack.empty()) {
|
||||
|
|
11
src/eval.h
11
src/eval.h
|
@ -21,12 +21,11 @@ public:
|
|||
private:
|
||||
std::optional<std::string> handle_special(std::string val, size_t &idx);
|
||||
std::optional<std::string> parse_macro(size_t &idx);
|
||||
std::optional<std::string> parse_macro_command(std::string val);
|
||||
std::optional<std::string> parse_register_command(std::string val);
|
||||
std::optional<std::string> parse_array_command(std::string val);
|
||||
std::optional<std::string> parse_base_n(const std::string& val);
|
||||
|
||||
void init_op_factory();
|
||||
std::optional<std::string> parse_macro_command(std::string token);
|
||||
std::optional<std::string> parse_register_command(std::string token);
|
||||
std::optional<std::string> parse_array_command(std::string token);
|
||||
std::optional<std::string> parse_base_n(const std::string& token);
|
||||
void init_environment();
|
||||
|
||||
using op_factory_t = std::function<std::unique_ptr<IOperation>()>;
|
||||
std::vector<std::string> expr;
|
||||
|
|
Loading…
Reference in New Issue