Started refactoring of the parser/evaluator method

This commit is contained in:
Marco Cetica 2024-03-08 11:42:57 +01:00
parent 207c387001
commit 505ed8b148
Signed by: marco
GPG Key ID: 45060A949E90D0FD
9 changed files with 231 additions and 195 deletions

View File

@ -6,6 +6,8 @@
#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) == '<' || \
@ -18,6 +20,41 @@
#define X_CONTAINS_Y(X, Y) ((Y.find_first_of(X) != std::string::npos))
void Evaluate::init_op_factory() {
// 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); });
// 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); });
}
std::optional<std::string> Evaluate::eval() {
for(size_t idx = 0; idx < this->expr.size(); idx++) {
auto val = this->expr.at(idx);
@ -27,110 +64,110 @@ std::optional<std::string> Evaluate::eval() {
// NUMERICAL OPERATIONS
//
if(val == "+") {
auto math = std::make_unique<Math>(OPType::ADD, this->parameters.precision);
err = math->exec(this->stack);
std::unique_ptr<IOperation> math = std::make_unique<Math>(OPType::ADD);
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::SUB, this->parameters.precision);
err = math->exec(this->stack);
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, this->parameters.precision);
err = math->exec(this->stack);
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, this->parameters.precision);
err = math->exec(this->stack);
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, this->parameters.precision);
err = math->exec(this->stack);
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, this->parameters.precision);
err = math->exec(this->stack);
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, this->parameters.precision);
err = math->exec(this->stack);
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, this->parameters.precision);
err = math->exec(this->stack);
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, this->parameters.precision);
err = math->exec(this->stack);
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, this->parameters.precision);
err = math->exec(this->stack);
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, this->parameters.precision);
err = math->exec(this->stack);
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, this->parameters.precision);
err = math->exec(this->stack);
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, this->parameters.precision);
err = math->exec(this->stack);
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, this->parameters.precision);
err = math->exec(this->stack);
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, this->parameters.precision);
err = math->exec(this->stack);
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, this->parameters.precision);
err = math->exec(this->stack);
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, this->parameters.precision);
err = math->exec(this->stack);
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, this->parameters.precision);
err = math->exec(this->stack);
auto math = std::make_unique<Math>(OPType::E);
err = math->exec(this->stack, this->parameters, this->regs);
if(err != std::nullopt) {
return err;
}
@ -139,74 +176,74 @@ std::optional<std::string> Evaluate::eval() {
// STACK OPERATIONS
//
else if(val == "p") { // PRINT TOP ELEMENT OF STACK
auto op = std::make_unique<Stack>(OPType::PCG, this->parameters.oradix);
err = op->exec(this->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, this->parameters.oradix);
err = op->exec(this->stack);
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, this->parameters.oradix);
err = op->exec(this->stack);
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, this->parameters.oradix);
err = op->exec(this->stack);
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, this->parameters.oradix);
err = op->exec(this->stack);
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);
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);
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);
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);
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, this->parameters.oradix);
err = op->exec(this->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);
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);
err = op->exec(this->stack, this->parameters, this->regs);
if(err != std::nullopt) {
return err;
}
@ -241,14 +278,14 @@ std::optional<std::string> Evaluate::eval() {
return err;
}
} else if(val == "x") { // EXECUTE MACRO
auto macro = std::make_unique<Macro>(OPType::EX, this->regs, this->parameters);
err = macro->exec(this->stack);
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, this->regs, this->parameters);
err = macro->exec(this->stack);
auto macro = std::make_unique<Macro>(OPType::RI);
err = macro->exec(this->stack, this->parameters, this->regs);
if(err != std::nullopt) {
return err;
}
@ -366,44 +403,44 @@ std::optional<std::string> Evaluate::parse_macro_command(std::string val) {
dc_register = val.at(1);
}
// Macro commands works as follow
// Macro commands works as follows
// Pop two values off the stack and compares them assuming
// they are numbers. If top-of-stack is greater,
// execute register's content as a macro
std::optional<std::string> err = std::nullopt;
if(operation == ">") {
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::GT, dc_register, this->regs, this->parameters);
err = macro->exec(this->stack);
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::GT, dc_register);
err = macro->exec(this->stack, this->parameters, this->regs);
if(err != std::nullopt) {
return err;
}
} else if(operation == "<") {
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::LT, dc_register, this->regs, this->parameters);
err = macro->exec(this->stack);
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::LT, dc_register);
err = macro->exec(this->stack, this->parameters, this->regs);
if(err != std::nullopt) {
return err;
}
} else if(operation == "=") {
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::EQ, dc_register, this->regs, this->parameters);
err = macro->exec(this->stack);
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::EQ, dc_register);
err = macro->exec(this->stack, this->parameters, this->regs);
if(err != std::nullopt) {
return err;
}
} else if(operation == ">=") {
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::GEQ, dc_register, this->regs, this->parameters);
err = macro->exec(this->stack);
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::GEQ, dc_register);
err = macro->exec(this->stack, this->parameters, this->regs);
if(err != std::nullopt) {
return err;
}
} else if(operation == "<=") {
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::LEQ, dc_register, this->regs, this->parameters);
err = macro->exec(this->stack);
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::LEQ, dc_register);
err = macro->exec(this->stack, this->parameters, this->regs);
if(err != std::nullopt) {
return err;
}
} else if(operation == "!=") {
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::NEQ, dc_register, this->regs, this->parameters);
err = macro->exec(this->stack);
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::NEQ, dc_register);
err = macro->exec(this->stack, this->parameters, this->regs);
if(err != std::nullopt) {
return err;
}

View File

@ -3,7 +3,10 @@
#include <vector>
#include <unordered_map>
#include <optional>
#include <memory>
#include <functional>
#include "operation.h"
#include "types.h"
class Evaluate {
@ -28,9 +31,12 @@ private:
std::optional<std::string> fn_get_oradix();
std::optional<std::string> fn_set_iradix();
std::optional<std::string> fn_get_iradix();
void init_op_factory();
using op_factory_t = std::function<std::unique_ptr<IOperation>()>;
std::vector<std::string> expr;
std::unordered_map<char, Register> &regs;
std::unordered_map<std::string, op_factory_t> op_factory;
dc_stack_t &stack;
Parameters &parameters;
};

View File

@ -7,20 +7,20 @@
#include "macro.h"
#include "is_num.h"
std::optional<std::string> Macro::exec(dc_stack_t &stack) {
std::optional<std::string> Macro::exec(dc_stack_t &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) {
std::optional<std::string> err = std::nullopt;
switch(this->op_type) {
case OPType::EX: err = fn_execute(stack); break;
case OPType::CMP: err = fn_evaluate_macro(stack); break;
case OPType::RI: err = fn_read_input(stack); break;
case OPType::EX: err = fn_execute(stack, parameters, regs); break;
case OPType::CMP: err = fn_evaluate_macro(stack, parameters, regs); break;
case OPType::RI: err = fn_read_input(stack, parameters, regs); break;
default: break;
}
return err;
}
std::optional<std::string> Macro::fn_execute(dc_stack_t &stack) {
std::optional<std::string> Macro::fn_execute(dc_stack_t &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) {
// Check if stack has enough elements
if(stack.empty()) {
return "This operation does not work on empty stack";
@ -32,7 +32,7 @@ std::optional<std::string> Macro::fn_execute(dc_stack_t &stack) {
if(!is_num<double>(head)) {
stack.pop_back();
std::vector<std::string> tokens = split(head);
Evaluate evaluator(tokens, this->regs, stack, this->parameters);
Evaluate evaluator(tokens, regs, stack, parameters);
auto err = evaluator.eval();
if(err != std::nullopt) {
@ -43,14 +43,14 @@ std::optional<std::string> Macro::fn_execute(dc_stack_t &stack) {
return std::nullopt;
}
std::optional<std::string> Macro::fn_evaluate_macro(dc_stack_t &stack) {
std::optional<std::string> Macro::fn_evaluate_macro(dc_stack_t &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) {
// Check whether the main stack has enough elements
if(stack.size() < 2) {
return "This operation requires two elements";
}
// Check whether the register's stack exists or not
if(this->regs.find(this->dc_register) == this->regs.end()) {
if(regs.find(this->dc_register) == regs.end()) {
return "Null register";
}
@ -59,7 +59,7 @@ std::optional<std::string> Macro::fn_evaluate_macro(dc_stack_t &stack) {
stack.pop_back();
auto second_str = stack.back();
stack.pop_back();
auto dc_macro = this->regs[this->dc_register].stack.back();
auto dc_macro = regs[this->dc_register].stack.back();
// Check if macro exists and if top two elements of main stack are numbers
if(!dc_macro.empty() && is_num<double>(head_str) && is_num<double>(second_str)) {
@ -70,7 +70,7 @@ std::optional<std::string> Macro::fn_evaluate_macro(dc_stack_t &stack) {
case Operator::GT: {
if(head > second) {
std::vector<std::string> tokens = split(dc_macro);
Evaluate evaluator(tokens, this->regs, stack, this->parameters);
Evaluate evaluator(tokens, regs, stack, parameters);
auto err = evaluator.eval();
if(err != std::nullopt) {
@ -82,7 +82,7 @@ std::optional<std::string> Macro::fn_evaluate_macro(dc_stack_t &stack) {
case Operator::LT: {
if(head < second) {
std::vector<std::string> tokens = split(dc_macro);
Evaluate evaluator(tokens, this->regs, stack, this->parameters);
Evaluate evaluator(tokens, regs, stack, parameters);
auto err = evaluator.eval();
if(err != std::nullopt) {
@ -94,7 +94,7 @@ std::optional<std::string> Macro::fn_evaluate_macro(dc_stack_t &stack) {
case Operator::EQ: {
if(head == second) {
std::vector<std::string> tokens = split(dc_macro);
Evaluate evaluator(tokens, this->regs, stack, this->parameters);
Evaluate evaluator(tokens, regs, stack, parameters);
auto err = evaluator.eval();
if(err != std::nullopt) {
@ -106,7 +106,7 @@ std::optional<std::string> Macro::fn_evaluate_macro(dc_stack_t &stack) {
case Operator::GEQ: {
if(head >= second) {
std::vector<std::string> tokens = split(dc_macro);
Evaluate evaluator(tokens, this->regs, stack, this->parameters);
Evaluate evaluator(tokens, regs, stack, parameters);
auto err = evaluator.eval();
if(err != std::nullopt) {
@ -118,7 +118,7 @@ std::optional<std::string> Macro::fn_evaluate_macro(dc_stack_t &stack) {
case Operator::LEQ: {
if(head <= second) {
std::vector<std::string> tokens = split(dc_macro);
Evaluate evaluator(tokens, this->regs, stack, this->parameters);
Evaluate evaluator(tokens, regs, stack, parameters);
auto err = evaluator.eval();
if(err != std::nullopt) {
@ -130,7 +130,7 @@ std::optional<std::string> Macro::fn_evaluate_macro(dc_stack_t &stack) {
case Operator::NEQ: {
if(head != second) {
std::vector<std::string> tokens = split(dc_macro);
Evaluate evaluator(tokens, this->regs, stack, this->parameters);
Evaluate evaluator(tokens, regs, stack, parameters);
auto err = evaluator.eval();
if(err != std::nullopt) {
@ -145,7 +145,7 @@ std::optional<std::string> Macro::fn_evaluate_macro(dc_stack_t &stack) {
return std::nullopt;
}
std::optional<std::string> Macro::fn_read_input(dc_stack_t &stack) {
std::optional<std::string> Macro::fn_read_input(dc_stack_t &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) {
// Read user input from stdin
std::string user_input;
@ -156,7 +156,7 @@ std::optional<std::string> Macro::fn_read_input(dc_stack_t &stack) {
// Push the input onto the main stack and execute it as a macro
stack.push_back(user_input);
Evaluate evaluator(this->regs, stack, this->parameters);
Evaluate evaluator(regs, stack, parameters);
auto err = evaluator.eval();
if(err != std::nullopt) {

View File

@ -8,21 +8,17 @@ enum class Operator {
class Macro : public IOperation {
public:
Macro(const OPType op_t, const Operator o, const char dc_r, std::unordered_map<char, Register> &r, Parameters &p)
: op_type(op_t), op(o), dc_register(dc_r), regs(r), parameters(p) {}
Macro(const OPType op_t, std::unordered_map<char, Register> &r, Parameters &p)
: op_type(op_t), regs(r), parameters(p) {}
std::optional<std::string> exec(dc_stack_t &stack) override;
Macro(const OPType op_t, const Operator o, __attribute__((unused)) const char dc_r) : op_type(op_t), op(o) {}
explicit Macro(const OPType op_t) : op_type(op_t) {}
std::optional<std::string> exec(dc_stack_t &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) override;
static std::vector<std::string> split(const std::string& str);
private:
std::optional<std::string> fn_execute(dc_stack_t &stack);
std::optional<std::string> fn_evaluate_macro(dc_stack_t &stack);
std::optional<std::string> fn_read_input(dc_stack_t &stack);
static std::optional<std::string> fn_execute(dc_stack_t &stack, Parameters &parameters, std::unordered_map<char, Register> &regs);
std::optional<std::string> fn_evaluate_macro(dc_stack_t &stack, Parameters &parameters, std::unordered_map<char, Register> &regs);
static std::optional<std::string> fn_read_input(dc_stack_t &stack, Parameters &parameters, std::unordered_map<char, Register> &regs);
OPType op_type;
Operator op{};
char dc_register{};
std::unordered_map<char, Register> &regs;
Parameters &parameters;
};

View File

@ -5,35 +5,35 @@
#include "math.h"
#include "is_num.h"
std::optional<std::string> Math::exec(dc_stack_t &stack) {
std::optional<std::string> Math::exec(dc_stack_t &stack, Parameters &parameters, __attribute__((unused)) std::unordered_map<char, Register> &regs) {
std::optional<std::string> err = std::nullopt;
switch(this->op_type) {
case OPType::ADD: err = fn_add(stack); break;
case OPType::SUB: err = fn_sub(stack); break;
case OPType::MUL: err = fn_mul(stack); break;
case OPType::DIV: err = fn_div(stack); break;
case OPType::MOD: err = fn_mod(stack); break;
case OPType::DIV_MOD: err = fn_div_mod(stack); break;
case OPType::MOD_EXP: err = fn_mod_exp(stack); break;
case OPType::EXP: err = fn_exp(stack); break;
case OPType::SQRT: err = fn_sqrt(stack); break;
case OPType::SIN: err = fn_sin(stack); break;
case OPType::COS: err = fn_cos(stack); break;
case OPType::TAN: err = fn_tan(stack); break;
case OPType::ASIN: err = fn_asin(stack); break;
case OPType::ACOS: err = fn_acos(stack); break;
case OPType::ATAN: err = fn_atan(stack); break;
case OPType::FACT: err = fn_fact(stack); break;
case OPType::PI: err = fn_pi(stack); break;
case OPType::E: err = fn_e(stack); break;
case OPType::ADD: err = fn_add(stack, parameters); break;
case OPType::SUB: err = fn_sub(stack, parameters); break;
case OPType::MUL: err = fn_mul(stack, parameters); break;
case OPType::DIV: err = fn_div(stack, parameters); break;
case OPType::MOD: err = fn_mod(stack, parameters); break;
case OPType::DIV_MOD: err = fn_div_mod(stack, parameters); break;
case OPType::MOD_EXP: err = fn_mod_exp(stack, parameters); break;
case OPType::EXP: err = fn_exp(stack, parameters); break;
case OPType::SQRT: err = fn_sqrt(stack, parameters); break;
case OPType::SIN: err = fn_sin(stack, parameters); break;
case OPType::COS: err = fn_cos(stack, parameters); break;
case OPType::TAN: err = fn_tan(stack, parameters); break;
case OPType::ASIN: err = fn_asin(stack, parameters); break;
case OPType::ACOS: err = fn_acos(stack, parameters); break;
case OPType::ATAN: err = fn_atan(stack, parameters); break;
case OPType::FACT: err = fn_fact(stack, parameters); break;
case OPType::PI: err = fn_pi(stack, parameters); break;
case OPType::E: err = fn_e(stack, parameters); break;
default: break;
}
return err;
}
std::optional<std::string> Math::fn_add(dc_stack_t &stack) const {
std::optional<std::string> Math::fn_add(dc_stack_t &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.size() < 2) {
return "'+' requires two operands";
@ -55,7 +55,7 @@ std::optional<std::string> Math::fn_add(dc_stack_t &stack) const {
stack.pop_back();
// Push back the result as a string
stack.push_back(trim_digits((lhs + rhs), this->precision));
stack.push_back(trim_digits((lhs + rhs), parameters.precision));
} else {
return "'+' requires numeric values";
}
@ -63,7 +63,7 @@ std::optional<std::string> Math::fn_add(dc_stack_t &stack) const {
return std::nullopt;
}
std::optional<std::string> Math::fn_sub(dc_stack_t &stack) const {
std::optional<std::string> Math::fn_sub(dc_stack_t &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.size() < 2) {
return "'-' requires two operands";
@ -95,7 +95,7 @@ std::optional<std::string> Math::fn_sub(dc_stack_t &stack) const {
}
// Push back the result as a string
stack.push_back(trim_digits(result, this->precision));
stack.push_back(trim_digits(result, parameters.precision));
} else {
return "'-' requires numeric values";
}
@ -103,7 +103,7 @@ std::optional<std::string> Math::fn_sub(dc_stack_t &stack) const {
return std::nullopt;
}
std::optional<std::string> Math::fn_mul(dc_stack_t &stack) const {
std::optional<std::string> Math::fn_mul(dc_stack_t &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.size() < 2) {
return "'*' requires two operands";
@ -125,7 +125,7 @@ std::optional<std::string> Math::fn_mul(dc_stack_t &stack) const {
stack.pop_back();
// Push back the result as a string
stack.push_back(trim_digits((lhs * rhs), this->precision));
stack.push_back(trim_digits((lhs * rhs), parameters.precision));
} else {
return "'*' requires numeric values";
}
@ -133,7 +133,7 @@ std::optional<std::string> Math::fn_mul(dc_stack_t &stack) const {
return std::nullopt;
}
std::optional<std::string> Math::fn_div(dc_stack_t &stack) const {
std::optional<std::string> Math::fn_div(dc_stack_t &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.size() < 2) {
return "'/' requires two operands";
@ -160,7 +160,7 @@ std::optional<std::string> Math::fn_div(dc_stack_t &stack) const {
}
// Push back the result as a string
stack.push_back(trim_digits((dividend / divisor), this->precision));
stack.push_back(trim_digits((dividend / divisor), parameters.precision));
} else {
return "'/' requires numeric values";
}
@ -168,7 +168,7 @@ std::optional<std::string> Math::fn_div(dc_stack_t &stack) const {
return std::nullopt;
}
std::optional<std::string> Math::fn_mod(dc_stack_t &stack) const {
std::optional<std::string> Math::fn_mod(dc_stack_t &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.size() < 2) {
return "'%' requires two operands";
@ -195,7 +195,7 @@ std::optional<std::string> Math::fn_mod(dc_stack_t &stack) const {
}
// Push back the result as a string
stack.push_back(trim_digits((static_cast<int>(lhs) % static_cast<int>(rhs)), this->precision));
stack.push_back(trim_digits((static_cast<int>(lhs) % static_cast<int>(rhs)), parameters.precision));
} else {
return "'%' requires numeric values";
}
@ -203,7 +203,7 @@ std::optional<std::string> Math::fn_mod(dc_stack_t &stack) const {
return std::nullopt;
}
std::optional<std::string> Math::fn_div_mod(dc_stack_t &stack) const {
std::optional<std::string> Math::fn_div_mod(dc_stack_t &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.size() < 2) {
return "'~' requires two operands";
@ -229,8 +229,8 @@ std::optional<std::string> Math::fn_div_mod(dc_stack_t &stack) const {
auto quotient = std::trunc(dividend / divisor);
auto remainder = ((int)dividend % (int)divisor);
stack.push_back(trim_digits(quotient, this->precision));
stack.push_back(trim_digits(remainder, this->precision));
stack.push_back(trim_digits(quotient, parameters.precision));
stack.push_back(trim_digits(remainder, parameters.precision));
}
} else {
@ -240,7 +240,7 @@ std::optional<std::string> Math::fn_div_mod(dc_stack_t &stack) const {
return std::nullopt;
}
std::optional<std::string> Math::fn_mod_exp(dc_stack_t &stack) const {
std::optional<std::string> Math::fn_mod_exp(dc_stack_t &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.size() < 3) {
return "'|' requires three operands";
@ -285,7 +285,7 @@ std::optional<std::string> Math::fn_mod_exp(dc_stack_t &stack) const {
c = (c * base) % modulus;
}
stack.push_back(trim_digits(c, this->precision));
stack.push_back(trim_digits(c, parameters.precision));
} else {
return "'|' requires numeric values";
}
@ -293,7 +293,7 @@ std::optional<std::string> Math::fn_mod_exp(dc_stack_t &stack) const {
return std::nullopt;
}
std::optional<std::string> Math::fn_exp(dc_stack_t &stack) const {
std::optional<std::string> Math::fn_exp(dc_stack_t &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.size() < 2) {
return "'^' requires two operands";
@ -315,7 +315,7 @@ std::optional<std::string> Math::fn_exp(dc_stack_t &stack) const {
stack.pop_back();
// Push back the result as a string
stack.push_back(trim_digits(pow(base, exp), this->precision));
stack.push_back(trim_digits(pow(base, exp), parameters.precision));
} else {
return "'^' requires numeric values";
}
@ -323,7 +323,7 @@ std::optional<std::string> Math::fn_exp(dc_stack_t &stack) const {
return std::nullopt;
}
std::optional<std::string> Math::fn_sqrt(dc_stack_t &stack) const {
std::optional<std::string> Math::fn_sqrt(dc_stack_t &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'v' requires one operand";
@ -344,7 +344,7 @@ std::optional<std::string> Math::fn_sqrt(dc_stack_t &stack) const {
}
// Push back the result as a string
stack.push_back(trim_digits(sqrt(val), this->precision));
stack.push_back(trim_digits(sqrt(val), parameters.precision));
} else {
return "'v' requires numeric values";
}
@ -352,7 +352,7 @@ std::optional<std::string> Math::fn_sqrt(dc_stack_t &stack) const {
return std::nullopt;
}
std::optional<std::string> Math::fn_sin(dc_stack_t &stack) const {
std::optional<std::string> Math::fn_sin(dc_stack_t &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'sin' requires one operand";
@ -369,7 +369,7 @@ std::optional<std::string> Math::fn_sin(dc_stack_t &stack) const {
stack.pop_back();
// Push back the result as a string
stack.push_back(trim_digits(sin(val), this->precision));
stack.push_back(trim_digits(sin(val), parameters.precision));
} else {
return "'sin' requires numeric values";
}
@ -377,7 +377,7 @@ std::optional<std::string> Math::fn_sin(dc_stack_t &stack) const {
return std::nullopt;
}
std::optional<std::string> Math::fn_cos(dc_stack_t &stack) const {
std::optional<std::string> Math::fn_cos(dc_stack_t &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'cos' requires one operand";
@ -394,7 +394,7 @@ std::optional<std::string> Math::fn_cos(dc_stack_t &stack) const {
stack.pop_back();
// Push back the result as a string
stack.push_back(trim_digits(cos(val), this->precision));
stack.push_back(trim_digits(cos(val), parameters.precision));
} else {
return "'cos' requires numeric values";
}
@ -402,7 +402,7 @@ std::optional<std::string> Math::fn_cos(dc_stack_t &stack) const {
return std::nullopt;
}
std::optional<std::string> Math::fn_tan(dc_stack_t &stack) const {
std::optional<std::string> Math::fn_tan(dc_stack_t &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'tan' requires one operand";
@ -419,7 +419,7 @@ std::optional<std::string> Math::fn_tan(dc_stack_t &stack) const {
stack.pop_back();
// Push back the result as a string
stack.push_back(trim_digits(tan(val), this->precision));
stack.push_back(trim_digits(tan(val), parameters.precision));
} else {
return "'tan' requires numeric values";
}
@ -427,7 +427,7 @@ std::optional<std::string> Math::fn_tan(dc_stack_t &stack) const {
return std::nullopt;
}
std::optional<std::string> Math::fn_asin(dc_stack_t &stack) const {
std::optional<std::string> Math::fn_asin(dc_stack_t &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'asin' requires one operand";
@ -444,7 +444,7 @@ std::optional<std::string> Math::fn_asin(dc_stack_t &stack) const {
stack.pop_back();
// Push back the result as a string
stack.push_back(trim_digits(asin(val), this->precision));
stack.push_back(trim_digits(asin(val), parameters.precision));
} else {
return "'asin' requires numeric values";
}
@ -452,7 +452,7 @@ std::optional<std::string> Math::fn_asin(dc_stack_t &stack) const {
return std::nullopt;
}
std::optional<std::string> Math::fn_acos(dc_stack_t &stack) const {
std::optional<std::string> Math::fn_acos(dc_stack_t &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'acos' requires one operand";
@ -469,7 +469,7 @@ std::optional<std::string> Math::fn_acos(dc_stack_t &stack) const {
stack.pop_back();
// Push back the result as a string
stack.push_back(trim_digits(acos(val), this->precision));
stack.push_back(trim_digits(acos(val), parameters.precision));
} else {
return "'acos' requires numeric values";
}
@ -477,7 +477,7 @@ std::optional<std::string> Math::fn_acos(dc_stack_t &stack) const {
return std::nullopt;
}
std::optional<std::string> Math::fn_atan(dc_stack_t &stack) const {
std::optional<std::string> Math::fn_atan(dc_stack_t &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'atan' requires one operand";
@ -494,7 +494,7 @@ std::optional<std::string> Math::fn_atan(dc_stack_t &stack) const {
stack.pop_back();
// Push back the result as a string
stack.push_back(trim_digits(atan(val), this->precision));
stack.push_back(trim_digits(atan(val), parameters.precision));
} else {
return "'atan' requires numeric values";
}
@ -502,7 +502,7 @@ std::optional<std::string> Math::fn_atan(dc_stack_t &stack) const {
return std::nullopt;
}
std::optional<std::string> Math::fn_fact(dc_stack_t &stack) const {
std::optional<std::string> Math::fn_fact(dc_stack_t &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'!' requires one operand";
@ -528,7 +528,7 @@ std::optional<std::string> Math::fn_fact(dc_stack_t &stack) const {
}
// Push back the result as a string
stack.push_back(trim_digits(static_cast<double>(factorial), this->precision));
stack.push_back(trim_digits(static_cast<double>(factorial), parameters.precision));
} else {
return "'!' requires numeric values";
}
@ -536,14 +536,14 @@ std::optional<std::string> Math::fn_fact(dc_stack_t &stack) const {
return std::nullopt;
}
std::optional<std::string> Math::fn_pi(dc_stack_t &stack) const {
stack.push_back(trim_digits(std::numbers::pi, this->precision));
std::optional<std::string> Math::fn_pi(dc_stack_t &stack, Parameters &parameters) {
stack.push_back(trim_digits(std::numbers::pi, parameters.precision));
return std::nullopt;
}
std::optional<std::string> Math::fn_e(dc_stack_t &stack) const {
stack.push_back(trim_digits(std::numbers::e, this->precision));
std::optional<std::string> Math::fn_e(dc_stack_t &stack, Parameters &parameters) {
stack.push_back(trim_digits(std::numbers::e, parameters.precision));
return std::nullopt;
}

View File

@ -4,30 +4,29 @@
class Math : public IOperation {
public:
Math(const OPType op_t, const unsigned int p) : op_type(op_t), precision(p) {}
std::optional<std::string> exec(dc_stack_t &stack) override;
explicit Math(const OPType op_t) : op_type(op_t) {}
std::optional<std::string> exec(dc_stack_t &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) override;
private:
std::optional<std::string> fn_add(dc_stack_t &stack) const;
std::optional<std::string> fn_sub(dc_stack_t &stack) const;
std::optional<std::string> fn_mul(dc_stack_t &stack) const;
std::optional<std::string> fn_div(dc_stack_t &stack) const;
std::optional<std::string> fn_mod(dc_stack_t &stack) const;
std::optional<std::string> fn_div_mod(dc_stack_t &stack) const;
std::optional<std::string> fn_mod_exp(dc_stack_t &stack) const;
std::optional<std::string> fn_exp(dc_stack_t &stack) const;
std::optional<std::string> fn_sqrt(dc_stack_t &stack) const;
std::optional<std::string> fn_sin(dc_stack_t &stack) const;
std::optional<std::string> fn_cos(dc_stack_t &stack) const;
std::optional<std::string> fn_tan(dc_stack_t &stack) const;
std::optional<std::string> fn_asin(dc_stack_t &stack) const;
std::optional<std::string> fn_acos(dc_stack_t &stack) const;
std::optional<std::string> fn_atan(dc_stack_t &stack) const;
std::optional<std::string> fn_fact(dc_stack_t &stack) const;
std::optional<std::string> fn_pi(dc_stack_t &stack) const;
std::optional<std::string> fn_e(dc_stack_t &stack) const;
static std::optional<std::string> fn_add(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_sub(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_mul(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_div(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_mod(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_div_mod(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_mod_exp(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_exp(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_sqrt(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_sin(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_cos(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_tan(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_asin(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_acos(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_atan(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_fact(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_pi(dc_stack_t &stack, Parameters &parameters) ;
static std::optional<std::string> fn_e(dc_stack_t &stack, Parameters &parameters) ;
static std::string trim_digits(double number, unsigned int precision);
OPType op_type;
unsigned int precision;
};

View File

@ -5,7 +5,7 @@
class IOperation {
public:
virtual std::optional<std::string> exec(dc_stack_t &stack) = 0;
virtual std::optional<std::string> exec(dc_stack_t &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) = 0;
virtual ~IOperation() = default;
};

View File

@ -5,21 +5,21 @@
#include "stack.h"
#include "is_num.h"
std::optional<std::string> Stack::exec(dc_stack_t &stack) {
std::optional<std::string> Stack::exec(dc_stack_t &stack, Parameters &parameters, __attribute__((unused)) std::unordered_map<char, Register> &regs) {
std::optional<std::string> err = std::nullopt;
auto print_oradix = [this, &stack](radix_base base) {
auto old_rdx = this->oradix;
this->oradix = base;
auto res = fn_print(stack, false);
this->oradix = old_rdx;
auto print_oradix = [&stack, &parameters, this](radix_base base) {
auto old_rdx = parameters.oradix;
parameters.oradix = base;
auto res = fn_print(stack, parameters, false);
parameters.oradix = old_rdx;
return res;
};
switch(this->op_type) {
case OPType::PCG: err = fn_print(stack, true); break;
case OPType::P: err = fn_print(stack, false); break;
case OPType::PCG: err = fn_print(stack, parameters, true); break;
case OPType::P: err = fn_print(stack, parameters, false); break;
case OPType::PBB: err = print_oradix(radix_base::BIN); break;
case OPType::PBO: err = print_oradix(radix_base::OCT); break;
case OPType::PBH: err = print_oradix(radix_base::HEX); break;
@ -27,7 +27,7 @@ std::optional<std::string> Stack::exec(dc_stack_t &stack) {
case OPType::PH: fn_pop_head(stack); break;
case OPType::SO: fn_swap_xy(stack); break;
case OPType::DP: fn_dup_head(stack); break;
case OPType::PS: fn_print_stack(stack); break;
case OPType::PS: fn_print_stack(stack, parameters); break;
case OPType::CH: fn_head_size(stack); break;
case OPType::CS: fn_stack_size(stack); break;
default: break;
@ -36,18 +36,18 @@ std::optional<std::string> Stack::exec(dc_stack_t &stack) {
return err;
}
std::optional<std::string> Stack::fn_print(dc_stack_t &stack, bool new_line) {
std::optional<std::string> Stack::fn_print(dc_stack_t &stack, Parameters &parameters, bool new_line) {
// Check if the stack is empty
if(stack.empty()) {
return "Cannot print empty stack";
}
// If the output radix is non-decimal, check if top of the stack is an integer
if(static_cast<int>(this->oradix) != 10 && !is_num<int>(stack.back())) {
if(static_cast<int>(parameters.oradix) != 10 && !is_num<int>(stack.back())) {
return "This output radix requires integer values";
}
switch(this->oradix) {
switch(parameters.oradix) {
case radix_base::DEC: {
if(new_line) {
std::cout << stack.back() << std::endl;
@ -117,8 +117,8 @@ std::optional<std::string> Stack::fn_dup_head(dc_stack_t &stack) {
return std::nullopt;
}
std::optional<std::string> Stack::fn_print_stack(dc_stack_t &stack) {
switch(this->oradix) {
std::optional<std::string> Stack::fn_print_stack(dc_stack_t &stack, Parameters &parameters) {
switch(parameters.oradix) {
case radix_base::DEC: {
for(auto & it : std::ranges::reverse_view(stack)) {
std::cout << it << std::endl;

View File

@ -5,19 +5,17 @@
class Stack : public IOperation {
public:
explicit Stack(const OPType op_t) : op_type(op_t) {}
Stack(const OPType op_t, const radix_base base) : op_type(op_t), oradix(base) {}
std::optional<std::string> exec(dc_stack_t &stack) override;
std::optional<std::string> exec(dc_stack_t &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) override;
private:
std::optional<std::string> fn_print(dc_stack_t &stack, bool new_line);
std::optional<std::string> fn_print(dc_stack_t &stack, Parameters &parameters, bool new_line);
static std::optional<std::string> fn_pop_head(dc_stack_t &stack);
static std::optional<std::string> fn_swap_xy(dc_stack_t &stack);
static std::optional<std::string> fn_dup_head(dc_stack_t &stack);
std::optional<std::string> fn_print_stack(dc_stack_t &stack);
std::optional<std::string> fn_print_stack(dc_stack_t &stack, Parameters &parameters);
static std::optional<std::string> fn_head_size(dc_stack_t &stack);
static std::optional<std::string> fn_stack_size(dc_stack_t &stack);
constexpr std::string to_bin(auto num);
OPType op_type;
radix_base oradix{};
};