Completed parser refactoring
dc / build (push) Has been cancelled Details

This commit is contained in:
Marco Cetica 2024-03-08 16:26:26 +01:00
parent d0ffb8610a
commit f349442410
Signed by: marco
GPG Key ID: 45060A949E90D0FD
3 changed files with 96 additions and 422 deletions

View File

@ -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">{
&quot;useNewFormat&quot;: 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">{
&quot;customColor&quot;: &quot;&quot;,
&quot;associatedIndex&quot;: 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>

View File

@ -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()) {

View File

@ -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;