Started refactoring of the parser/evaluator method
This commit is contained in:
parent
207c387001
commit
505ed8b148
179
src/eval.cpp
179
src/eval.cpp
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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> ®s;
|
||||
std::unordered_map<std::string, op_factory_t> op_factory;
|
||||
dc_stack_t &stack;
|
||||
Parameters ¶meters;
|
||||
};
|
||||
|
|
|
@ -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 ¶meters, std::unordered_map<char, Register> ®s) {
|
||||
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 ¶meters, std::unordered_map<char, Register> ®s) {
|
||||
// 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 ¶meters, std::unordered_map<char, Register> ®s) {
|
||||
// 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 ¶meters, std::unordered_map<char, Register> ®s) {
|
||||
// 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) {
|
||||
|
|
16
src/macro.h
16
src/macro.h
|
@ -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 ¶meters, std::unordered_map<char, Register> ®s) 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 ¶meters, std::unordered_map<char, Register> ®s);
|
||||
std::optional<std::string> fn_evaluate_macro(dc_stack_t &stack, Parameters ¶meters, std::unordered_map<char, Register> ®s);
|
||||
static std::optional<std::string> fn_read_input(dc_stack_t &stack, Parameters ¶meters, std::unordered_map<char, Register> ®s);
|
||||
|
||||
OPType op_type;
|
||||
Operator op{};
|
||||
char dc_register{};
|
||||
std::unordered_map<char, Register> ®s;
|
||||
Parameters ¶meters;
|
||||
};
|
||||
|
|
112
src/math.cpp
112
src/math.cpp
|
@ -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 ¶meters, __attribute__((unused)) std::unordered_map<char, Register> ®s) {
|
||||
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 ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
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 ¶meters) {
|
||||
stack.push_back(trim_digits(std::numbers::e, parameters.precision));
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
41
src/math.h
41
src/math.h
|
@ -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 ¶meters, std::unordered_map<char, Register> ®s) 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 ¶meters) ;
|
||||
static std::optional<std::string> fn_sub(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_mul(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_div(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_mod(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_div_mod(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_mod_exp(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_exp(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_sqrt(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_sin(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_cos(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_tan(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_asin(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_acos(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_atan(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_fact(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_pi(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_e(dc_stack_t &stack, Parameters ¶meters) ;
|
||||
static std::string trim_digits(double number, unsigned int precision);
|
||||
|
||||
OPType op_type;
|
||||
unsigned int precision;
|
||||
};
|
||||
|
|
|
@ -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 ¶meters, std::unordered_map<char, Register> ®s) = 0;
|
||||
virtual ~IOperation() = default;
|
||||
};
|
||||
|
||||
|
|
|
@ -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 ¶meters, __attribute__((unused)) std::unordered_map<char, Register> ®s) {
|
||||
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, ¶meters, 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 ¶meters, 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 ¶meters) {
|
||||
switch(parameters.oradix) {
|
||||
case radix_base::DEC: {
|
||||
for(auto & it : std::ranges::reverse_view(stack)) {
|
||||
std::cout << it << std::endl;
|
||||
|
|
|
@ -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 ¶meters, std::unordered_map<char, Register> ®s) 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 ¶meters, 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 ¶meters);
|
||||
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{};
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue