Refactored DC data structure
dc / build (push) Successful in 58s Details

This commit is contained in:
Marco Cetica 2024-03-11 16:37:55 +01:00
parent 4b533331f4
commit aebfec4fb3
Signed by: marco
GPG Key ID: 45060A949E90D0FD
17 changed files with 328 additions and 256 deletions

View File

@ -2,15 +2,21 @@ cmake_minimum_required(VERSION 3.12)
project(dc)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \
-Wall -Wextra -Werror -pedantic-errors \
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} \
-Wall -Wextra -pedantic -Werror \
-fstack-protector-strong -D_FORTIFY_SOURCE=2 \
-Wformat-security -fsanitize=address -fsanitize=undefined \
-fstack-clash-protection -Wundef -Wshadow -Wpointer-arith \
-Wcast-align -Wwrite-strings -ftrapv -std=c++20 -O3")
-Wcast-align -Wwrite-strings -ftrapv -std=c++20 -g -O2")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -std=c++20")
add_executable(dc main.cpp)
include_directories(src)
add_subdirectory(src)
target_link_libraries(dc src)
target_link_libraries(dc src)

View File

@ -54,7 +54,7 @@ And much more. You can find the complete manual [here](https://github.com/ice-bi
the following command:
```sh
$> mkdir build && cd build
$> cmake .. && make
$> cmake -DCMAKE_BUILD_TYPE=Release .. && make
```
A new statically-compiled binary called `dc` will be created in your local folder. To generate a man page from the `man.md` document,
use the following command(note: needs pandoc):

View File

@ -5,7 +5,7 @@
#include <iterator>
#include <fstream>
#include "src/types.h"
#include "src//adt.h"
#include "src/eval.h"
#include "src/macro.h" // for split static method
@ -27,7 +27,7 @@ int main(int argc, char **argv) {
std::string stdin_expression;
bool execute_expression = false;
bool execute_file = false;
dc_stack_t stack;
DCStack<std::string> stack;
std::unordered_map<char, Register> regs;
Parameters parameters = {
.precision = 0,

View File

@ -1,17 +1,20 @@
project(src)
set(HEADER_FILES
eval.h
macro.h
math.h
operation.h
stack.h
types.h)
eval.h
macro.h
math.h
operation.h
stack.h
adt.h
)
set(SOURCE_FILES
eval.cpp
macro.cpp
math.cpp
stack.cpp)
eval.cpp
macro.cpp
math.cpp
stack.cpp
adt.cpp
)
add_library(src STATIC ${SOURCE_FILES} ${HEADER_FILES})
add_library(src STATIC ${SOURCE_FILES} ${HEADER_FILES})

76
src/adt.cpp Normal file
View File

@ -0,0 +1,76 @@
#include "adt.h"
/**
* Add new element to the stack
*/
template<typename T>
requires is_num_or_str<T>
void DCStack<T>::push(T value) {
this->stack.push_back(value);
}
/**
* Clear the stack
*/
template<typename T>
requires is_num_or_str<T>
void DCStack<T>::clear() {
if(!this->stack.empty()) {
this->stack.clear();
}
}
/**
* If @remove is true, pop head of the stack
* otherwise return it without popping.
* If stack is empty it causes undefined behavior
*/
template<typename T>
requires is_num_or_str<T>
T DCStack<T>::pop(bool remove) {
T value = this->stack.back();
if(remove) {
this->stack.pop_back();
}
return value;
}
/**
* Read stack at index
*/
template<typename T>
requires is_num_or_str<T>
T& DCStack<T>::at(size_t index) {
T &value = this->stack.at(index);
return value;
}
/**
* Returns stack size
*/
template<typename T>
requires is_num_or_str<T>
size_t DCStack<T>::size() {
return this->stack.size();
}
/**
* Returns true if stack is empty
* false otherwise
*/
template<typename T>
requires is_num_or_str<T>
bool DCStack<T>::empty() {
return this->stack.empty();
}
/**
* Returns a const reference to the stack
*/
template<typename T>
requires is_num_or_str<T>
const std::vector<T>& DCStack<T>::get_ref() const {
return this->stack;
}

40
src/adt.h Normal file
View File

@ -0,0 +1,40 @@
#pragma once
#include <vector>
#include <string>
#include <cstdint>
#include <unordered_map>
template<typename T>
concept is_num_or_str = (std::is_arithmetic_v<T> || std::is_same_v<T, std::string>);
template<typename T>
requires is_num_or_str<T>
class DCStack {
public:
DCStack() = default;
void push(T value);
void clear();
T pop(bool remove);
T& at(size_t index);
size_t size();
bool empty();
[[nodiscard]] const std::vector<T>& get_ref() const;
private:
std::vector<T> stack;
T last_x;
T last_y;
T last_z;
};
typedef struct {
DCStack<std::string> stack;
std::unordered_map<int, std::string> array;
} Register;
enum class radix_base : std::uint8_t { BIN = 2, OCT = 8, DEC = 10, HEX = 16 };
typedef struct {
unsigned int precision;
unsigned short iradix;
radix_base oradix;
} Parameters;

View File

@ -1,5 +1,6 @@
#include <memory>
#include "adt.cpp"
#include "eval.h"
#include "math.h"
#include "stack.h"
@ -86,7 +87,7 @@ std::optional<std::string> Evaluate::eval() {
} else if(this->parameters.iradix != 10) {
err = parse_base_n(token);
} else if(is_num<double>(token)) {
this->stack.push_back(token);
this->stack.push(token);
} else if(token == "q") {
std::exit(0);
} else {
@ -110,7 +111,7 @@ std::optional<std::string> Evaluate::parse_base_n(const std::string& token) {
// Try to convert the number to the selected numeric base
try {
long number = std::stol(token, nullptr, this->parameters.iradix);
this->stack.push_back(std::to_string(number));
this->stack.push(std::to_string(number));
} catch(...) {
return "Invalid number for input base '"
+ std::to_string(this->parameters.iradix) + "'";
@ -159,7 +160,7 @@ std::optional<std::string> Evaluate::parse_macro(size_t &idx) {
}
// Push the macro back onto the stack
this->stack.push_back(dc_macro);
this->stack.push(dc_macro);
return std::nullopt;
}
@ -239,21 +240,20 @@ std::optional<std::string> Evaluate::parse_register_command(std::string token) {
// Otherwise pop an element from main stack and store it into
// the register's top-of-the-stack. Any previous value gets overwritten
auto reg_name = token.at(1);
auto head = this->stack.back();
this->stack.pop_back();
auto head = this->stack.pop(true);
// Always discard previous instance of the register
// i.e., initialize a new instance of register 'reg_name'
this->regs.erase(reg_name);
this->regs.insert(
std::make_pair(reg_name, Register{
std::vector<std::string>(),
DCStack<std::string>(),
std::unordered_map<int, std::string>()
})
);
// Populate register's 'reg_name' stack with top of main stack
this->regs[reg_name].stack.push_back(head);
this->regs[reg_name].stack.push(head);
} else if(token.at(0) == 'S') {
// An uppercase 'S' pops the top of the main stack and
// pushes it onto the stack of selected register.
@ -266,17 +266,16 @@ std::optional<std::string> Evaluate::parse_register_command(std::string token) {
}
auto reg_name = token.at(1);
auto head = this->stack.back();
this->stack.pop_back();
auto head = this->stack.pop(true);
// If register's stack exist, push an element onto its stack
// otherwise allocate a new instance of the register
auto it = this->regs.find(reg_name);
if(it != this->regs.end()) { // Register exists
it->second.stack.push_back(head);
it->second.stack.push(head);
} else { // Register doesn't exist
this->regs[reg_name] = Register{
std::vector<std::string>{head},
DCStack<std::string>(),
std::unordered_map<int, std::string>()
};
}
@ -297,9 +296,8 @@ std::optional<std::string> Evaluate::parse_register_command(std::string token) {
}
// Otherwise, pop an element from the register's stack and push it onto the main stack
auto value = this->regs[reg_name].stack.back();
this->regs[reg_name].stack.pop_back();
this->stack.push_back(value);
auto value = this->regs[reg_name].stack.pop(true);
this->stack.push(value);
} else {
// Otherwise retrieve the register name and push its value
// to the stack without altering the register's stack.
@ -309,13 +307,13 @@ std::optional<std::string> Evaluate::parse_register_command(std::string token) {
// If register does not exist or its stack is empty, push '0' onto the main stack
auto it = this->regs.find(reg_name);
if(it == this->regs.end() || it->second.stack.empty()) {
this->stack.emplace_back("0");
this->stack.push("0");
return std::nullopt;
}
// Otherwise, peek an element from the register's stack and push it onto the main stack
auto value = this->regs[reg_name].stack.back();
this->stack.push_back(value);
auto value = this->regs[reg_name].stack.pop(false);
this->stack.push(value);
}
return std::nullopt;
@ -336,10 +334,8 @@ std::optional<std::string> Evaluate::parse_array_command(std::string token) {
}
// Extract two elements from the main stack
auto idx_str = this->stack.back();
this->stack.pop_back();
auto arr_val = this->stack.back();
this->stack.pop_back();
auto idx_str = this->stack.pop(true);
auto arr_val = this->stack.pop(true);
// Check whether the index is an integer
if(!is_num<int>(idx_str)) {
@ -358,7 +354,7 @@ std::optional<std::string> Evaluate::parse_array_command(std::string token) {
it->second.array.insert(std::pair<int, std::string>(idx, arr_val));
} else { // Register doesn't exist
this->regs[reg_name] = Register{
std::vector<std::string>(),
DCStack<std::string>(),
std::unordered_map<int, std::string>{{idx, arr_val}}
};
}
@ -373,8 +369,7 @@ std::optional<std::string> Evaluate::parse_array_command(std::string token) {
}
// Extract the index from the stack
auto idx_str = this->stack.back();
this->stack.pop_back();
auto idx_str = this->stack.pop(true);
// Check if index is an integer
if(!is_num<int>(idx_str)) {
@ -400,7 +395,7 @@ std::optional<std::string> Evaluate::parse_array_command(std::string token) {
auto arr_it = reg_it->second.array.find(idx);
if(arr_it != reg_it->second.array.end()) {
this->stack.push_back(arr_it->second);
this->stack.push(arr_it->second);
} else {
return std::string("Cannot access ") + reg_name +
std::string("[") + std::to_string(idx) + std::string("]");

View File

@ -6,15 +6,15 @@
#include <memory>
#include <functional>
#include "adt.h"
#include "operation.h"
#include "types.h"
class Evaluate {
public:
Evaluate(const std::vector<std::string>& e, std::unordered_map<char, Register> &r,
dc_stack_t &s, Parameters &p)
DCStack<std::string> &s, Parameters &p)
: expr(e), regs(r), stack(s), parameters(p) {}
Evaluate(std::unordered_map<char, Register> &r, dc_stack_t &s, Parameters &p)
Evaluate(std::unordered_map<char, Register> &r, DCStack<std::string> &s, Parameters &p)
: regs(r), stack(s), parameters(p) {}
std::optional<std::string> eval();
@ -30,6 +30,6 @@ private:
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;
DCStack<std::string> &stack;
Parameters &parameters;
};

View File

@ -5,7 +5,8 @@ template <typename T>
concept Numeric = std::is_arithmetic_v<T>;
template <typename T>
bool is_num(const std::string &str) requires Numeric<T> {
requires Numeric<T>
bool is_num(const std::string &str) {
std::istringstream ss(str);
T number;

View File

@ -3,11 +3,12 @@
#include <iterator>
#include <limits>
#include "adt.cpp"
#include "eval.h"
#include "macro.h"
#include "is_num.h"
std::optional<std::string> Macro::exec(dc_stack_t &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) {
std::optional<std::string> Macro::exec(DCStack<std::string> &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) {
std::optional<std::string> err = std::nullopt;
switch(this->op_type) {
@ -20,7 +21,7 @@ std::optional<std::string> Macro::exec(dc_stack_t &stack, Parameters &parameters
return err;
}
std::optional<std::string> Macro::fn_execute(dc_stack_t &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) {
std::optional<std::string> Macro::fn_execute(DCStack<std::string> &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";
@ -28,9 +29,9 @@ std::optional<std::string> Macro::fn_execute(dc_stack_t &stack, Parameters &para
// If the head of the stack is a string
// pop it and execute it as a macro
auto head = stack.back();
auto head = stack.pop(false);
if(!is_num<double>(head)) {
stack.pop_back();
stack.pop(true);
std::vector<std::string> tokens = split(head);
Evaluate evaluator(tokens, regs, stack, parameters);
@ -43,7 +44,7 @@ std::optional<std::string> Macro::fn_execute(dc_stack_t &stack, Parameters &para
return std::nullopt;
}
std::optional<std::string> Macro::fn_evaluate_macro(dc_stack_t &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) {
std::optional<std::string> Macro::fn_evaluate_macro(DCStack<std::string> &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";
@ -55,11 +56,9 @@ std::optional<std::string> Macro::fn_evaluate_macro(dc_stack_t &stack, Parameter
}
// Extract macro and top two values of the stack
auto head_str = stack.back();
stack.pop_back();
auto second_str = stack.back();
stack.pop_back();
auto dc_macro = regs[this->dc_register].stack.back();
auto head_str = stack.pop(true);
auto second_str = stack.pop(true);
auto dc_macro = regs[this->dc_register].stack.pop(false);
// 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)) {
@ -145,7 +144,7 @@ std::optional<std::string> Macro::fn_evaluate_macro(dc_stack_t &stack, Parameter
return std::nullopt;
}
std::optional<std::string> Macro::fn_read_input(dc_stack_t &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) {
std::optional<std::string> Macro::fn_read_input(DCStack<std::string> &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) {
// Read user input from stdin
std::string user_input;
@ -155,7 +154,7 @@ std::optional<std::string> Macro::fn_read_input(dc_stack_t &stack, Parameters &p
}
// Push the input onto the main stack and execute it as a macro
stack.push_back(user_input);
stack.push(user_input);
Evaluate evaluator(regs, stack, parameters);
auto err = evaluator.eval();

View File

@ -10,13 +10,13 @@ class Macro : public IOperation {
public:
Macro(const OPType op_t, const Operator o, const char dc_r) : op_type(op_t), op(o), dc_register(dc_r) {}
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;
std::optional<std::string> exec(DCStack<std::string> &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) override;
static std::vector<std::string> split(const std::string& str);
private:
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);
static std::optional<std::string> fn_execute(DCStack<std::string> &stack, Parameters &parameters, std::unordered_map<char, Register> &regs);
std::optional<std::string> fn_evaluate_macro(DCStack<std::string> &stack, Parameters &parameters, std::unordered_map<char, Register> &regs);
static std::optional<std::string> fn_read_input(DCStack<std::string> &stack, Parameters &parameters, std::unordered_map<char, Register> &regs);
OPType op_type;
Operator op{};

View File

@ -2,10 +2,11 @@
#include <numbers>
#include <iomanip>
#include "adt.cpp"
#include "math.h"
#include "is_num.h"
std::optional<std::string> Math::exec(dc_stack_t &stack, Parameters &parameters, __attribute__((unused)) std::unordered_map<char, Register> &regs) {
std::optional<std::string> Math::exec(DCStack<std::string> &stack, Parameters &parameters, __attribute__((unused)) std::unordered_map<char, Register> &regs) {
std::optional<std::string> err = std::nullopt;
switch(this->op_type) {
@ -33,7 +34,7 @@ std::optional<std::string> Math::exec(dc_stack_t &stack, Parameters &parameters,
return err;
}
std::optional<std::string> Math::fn_add(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Math::fn_add(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.size() < 2) {
return "'+' requires two operands";
@ -48,14 +49,11 @@ std::optional<std::string> Math::fn_add(dc_stack_t &stack, Parameters &parameter
// Check whether both entries are numbers
if(is_x_num && is_y_num) {
auto lhs = std::stod(stack.back());
stack.pop_back();
auto rhs = std::stod(stack.back());
stack.pop_back();
auto lhs = std::stod(stack.pop(true));
auto rhs = std::stod(stack.pop(true));
// Push back the result as a string
stack.push_back(trim_digits((lhs + rhs), parameters.precision));
stack.push(trim_digits((lhs + rhs), parameters.precision));
} else {
return "'+' requires numeric values";
}
@ -63,7 +61,7 @@ std::optional<std::string> Math::fn_add(dc_stack_t &stack, Parameters &parameter
return std::nullopt;
}
std::optional<std::string> Math::fn_sub(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Math::fn_sub(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.size() < 2) {
return "'-' requires two operands";
@ -78,11 +76,8 @@ std::optional<std::string> Math::fn_sub(dc_stack_t &stack, Parameters &parameter
// Check whether both entries are numbers
if(is_x_num && is_y_num) {
auto lhs = std::stod(stack.back());
stack.pop_back();
auto rhs = std::stod(stack.back());
stack.pop_back();
auto lhs = std::stod(stack.pop(true));
auto rhs = std::stod(stack.pop(true));
// Subtract the two operands
auto result = (-(lhs - rhs));
@ -95,7 +90,7 @@ std::optional<std::string> Math::fn_sub(dc_stack_t &stack, Parameters &parameter
}
// Push back the result as a string
stack.push_back(trim_digits(result, parameters.precision));
stack.push(trim_digits(result, parameters.precision));
} else {
return "'-' requires numeric values";
}
@ -103,7 +98,7 @@ std::optional<std::string> Math::fn_sub(dc_stack_t &stack, Parameters &parameter
return std::nullopt;
}
std::optional<std::string> Math::fn_mul(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Math::fn_mul(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.size() < 2) {
return "'*' requires two operands";
@ -118,14 +113,11 @@ std::optional<std::string> Math::fn_mul(dc_stack_t &stack, Parameters &parameter
// Check whether both entries are numbers
if(is_x_num && is_y_num) {
auto lhs = std::stod(stack.back());
stack.pop_back();
auto rhs = std::stod(stack.back());
stack.pop_back();
auto lhs = std::stod(stack.pop(true));
auto rhs = std::stod(stack.pop(true));
// Push back the result as a string
stack.push_back(trim_digits((lhs * rhs), parameters.precision));
stack.push(trim_digits((lhs * rhs), parameters.precision));
} else {
return "'*' requires numeric values";
}
@ -133,7 +125,7 @@ std::optional<std::string> Math::fn_mul(dc_stack_t &stack, Parameters &parameter
return std::nullopt;
}
std::optional<std::string> Math::fn_div(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Math::fn_div(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.size() < 2) {
return "'/' requires two operands";
@ -148,11 +140,8 @@ std::optional<std::string> Math::fn_div(dc_stack_t &stack, Parameters &parameter
// Check whether both entries are numbers
if(is_x_num && is_y_num) {
auto divisor = std::stod(stack.back());
stack.pop_back();
auto dividend = std::stod(stack.back());
stack.pop_back();
auto divisor = std::stod(stack.pop(true));
auto dividend = std::stod(stack.pop(true));
// Check whether divisor is equal to zero
if(divisor == 0.0) {
@ -160,7 +149,7 @@ std::optional<std::string> Math::fn_div(dc_stack_t &stack, Parameters &parameter
}
// Push back the result as a string
stack.push_back(trim_digits((dividend / divisor), parameters.precision));
stack.push(trim_digits((dividend / divisor), parameters.precision));
} else {
return "'/' requires numeric values";
}
@ -168,7 +157,7 @@ std::optional<std::string> Math::fn_div(dc_stack_t &stack, Parameters &parameter
return std::nullopt;
}
std::optional<std::string> Math::fn_mod(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Math::fn_mod(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.size() < 2) {
return "'%' requires two operands";
@ -183,11 +172,8 @@ std::optional<std::string> Math::fn_mod(dc_stack_t &stack, Parameters &parameter
// Check whether both entries are numbers
if(is_x_num && is_y_num) {
auto rhs = std::stod(stack.back());
stack.pop_back();
auto lhs = std::stod(stack.back());
stack.pop_back();
auto rhs = std::stod(stack.pop(true));
auto lhs = std::stod(stack.pop(true));
// Check whether divisor is equal to zero
if(rhs == 0.0) {
@ -195,7 +181,7 @@ std::optional<std::string> Math::fn_mod(dc_stack_t &stack, Parameters &parameter
}
// Push back the result as a string
stack.push_back(trim_digits((static_cast<int>(lhs) % static_cast<int>(rhs)), parameters.precision));
stack.push(trim_digits((static_cast<int>(lhs) % static_cast<int>(rhs)), parameters.precision));
} else {
return "'%' requires numeric values";
}
@ -203,7 +189,7 @@ std::optional<std::string> Math::fn_mod(dc_stack_t &stack, Parameters &parameter
return std::nullopt;
}
std::optional<std::string> Math::fn_div_mod(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Math::fn_div_mod(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.size() < 2) {
return "'~' requires two operands";
@ -218,19 +204,16 @@ std::optional<std::string> Math::fn_div_mod(dc_stack_t &stack, Parameters &param
// Check whether both entries are numbers
if(is_x_num && is_y_num) {
auto divisor = std::stod(stack.back());
stack.pop_back();
auto dividend = std::stod(stack.back());
stack.pop_back();
auto divisor = std::stod(stack.pop(true));
auto dividend = std::stod(stack.pop(true));
// Check if divisor is not equal to zero
if(divisor != 0.0) {
auto quotient = std::trunc(dividend / divisor);
auto remainder = ((int)dividend % (int)divisor);
stack.push_back(trim_digits(quotient, parameters.precision));
stack.push_back(trim_digits(remainder, parameters.precision));
stack.push(trim_digits(quotient, parameters.precision));
stack.push(trim_digits(remainder, parameters.precision));
}
} else {
@ -240,7 +223,7 @@ std::optional<std::string> Math::fn_div_mod(dc_stack_t &stack, Parameters &param
return std::nullopt;
}
std::optional<std::string> Math::fn_mod_exp(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Math::fn_mod_exp(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.size() < 3) {
return "'|' requires three operands";
@ -260,17 +243,12 @@ std::optional<std::string> Math::fn_mod_exp(dc_stack_t &stack, Parameters &param
// This functions computes
// c ≡ b^e (mod n)
if(is_n_num && is_e_num && is_b_num) {
auto modulus = std::stoi(stack.back());
stack.pop_back();
auto exponent = std::stoi(stack.back());
stack.pop_back();
auto base = std::stoi(stack.back());
stack.pop_back();
auto modulus = std::stoi(stack.pop(true));
auto exponent = std::stoi(stack.pop(true));
auto base = std::stoi(stack.pop(true));
if(modulus == 1) {
stack.emplace_back("0");
stack.push("0");
return std::nullopt;
} else if(modulus == 0) {
return "Modulus cannot be zero";
@ -285,7 +263,7 @@ std::optional<std::string> Math::fn_mod_exp(dc_stack_t &stack, Parameters &param
c = (c * base) % modulus;
}
stack.push_back(trim_digits(c, parameters.precision));
stack.push(trim_digits(c, parameters.precision));
} else {
return "'|' requires numeric values";
}
@ -293,7 +271,7 @@ std::optional<std::string> Math::fn_mod_exp(dc_stack_t &stack, Parameters &param
return std::nullopt;
}
std::optional<std::string> Math::fn_exp(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Math::fn_exp(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.size() < 2) {
return "'^' requires two operands";
@ -308,14 +286,11 @@ std::optional<std::string> Math::fn_exp(dc_stack_t &stack, Parameters &parameter
// Check whether both entries are numbers
if(is_x_num && is_y_num) {
auto exp = std::stod(stack.back());
stack.pop_back();
auto base = std::stod(stack.back());
stack.pop_back();
auto exp = std::stod(stack.pop(true));
auto base = std::stod(stack.pop(true));
// Push back the result as a string
stack.push_back(trim_digits(pow(base, exp), parameters.precision));
stack.push(trim_digits(pow(base, exp), parameters.precision));
} else {
return "'^' requires numeric values";
}
@ -323,7 +298,7 @@ std::optional<std::string> Math::fn_exp(dc_stack_t &stack, Parameters &parameter
return std::nullopt;
}
std::optional<std::string> Math::fn_sqrt(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Math::fn_sqrt(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'v' requires one operand";
@ -336,15 +311,14 @@ std::optional<std::string> Math::fn_sqrt(dc_stack_t &stack, Parameters &paramete
// Check whether the entry is a number
if(is_x_num) {
auto val = std::stod(stack.back());
stack.pop_back();
auto val = std::stod(stack.pop(true));
if(val <= 0.0) {
return "'v' domain error";
}
// Push back the result as a string
stack.push_back(trim_digits(sqrt(val), parameters.precision));
stack.push(trim_digits(sqrt(val), parameters.precision));
} else {
return "'v' requires numeric values";
}
@ -352,7 +326,7 @@ std::optional<std::string> Math::fn_sqrt(dc_stack_t &stack, Parameters &paramete
return std::nullopt;
}
std::optional<std::string> Math::fn_sin(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Math::fn_sin(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'sin' requires one operand";
@ -365,11 +339,10 @@ std::optional<std::string> Math::fn_sin(dc_stack_t &stack, Parameters &parameter
// Check whether the entry is a number
if(is_x_num) {
auto val = std::stod(stack.back());
stack.pop_back();
auto val = std::stod(stack.pop(true));
// Push back the result as a string
stack.push_back(trim_digits(sin(val), parameters.precision));
stack.push(trim_digits(sin(val), parameters.precision));
} else {
return "'sin' requires numeric values";
}
@ -377,7 +350,7 @@ std::optional<std::string> Math::fn_sin(dc_stack_t &stack, Parameters &parameter
return std::nullopt;
}
std::optional<std::string> Math::fn_cos(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Math::fn_cos(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'cos' requires one operand";
@ -390,11 +363,10 @@ std::optional<std::string> Math::fn_cos(dc_stack_t &stack, Parameters &parameter
// Check whether the entry is a number
if(is_x_num) {
auto val = std::stod(stack.back());
stack.pop_back();
auto val = std::stod(stack.pop(true));
// Push back the result as a string
stack.push_back(trim_digits(cos(val), parameters.precision));
stack.push(trim_digits(cos(val), parameters.precision));
} else {
return "'cos' requires numeric values";
}
@ -402,7 +374,7 @@ std::optional<std::string> Math::fn_cos(dc_stack_t &stack, Parameters &parameter
return std::nullopt;
}
std::optional<std::string> Math::fn_tan(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Math::fn_tan(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'tan' requires one operand";
@ -415,11 +387,10 @@ std::optional<std::string> Math::fn_tan(dc_stack_t &stack, Parameters &parameter
// Check whether the entry is a number
if(is_x_num) {
auto val = std::stod(stack.back());
stack.pop_back();
auto val = std::stod(stack.pop(true));
// Push back the result as a string
stack.push_back(trim_digits(tan(val), parameters.precision));
stack.push(trim_digits(tan(val), parameters.precision));
} else {
return "'tan' requires numeric values";
}
@ -427,7 +398,7 @@ std::optional<std::string> Math::fn_tan(dc_stack_t &stack, Parameters &parameter
return std::nullopt;
}
std::optional<std::string> Math::fn_asin(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Math::fn_asin(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'asin' requires one operand";
@ -440,11 +411,10 @@ std::optional<std::string> Math::fn_asin(dc_stack_t &stack, Parameters &paramete
// Check whether the entry is a number
if(is_x_num) {
auto val = std::stod(stack.back());
stack.pop_back();
auto val = std::stod(stack.pop(true));
// Push back the result as a string
stack.push_back(trim_digits(asin(val), parameters.precision));
stack.push(trim_digits(asin(val), parameters.precision));
} else {
return "'asin' requires numeric values";
}
@ -452,7 +422,7 @@ std::optional<std::string> Math::fn_asin(dc_stack_t &stack, Parameters &paramete
return std::nullopt;
}
std::optional<std::string> Math::fn_acos(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Math::fn_acos(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'acos' requires one operand";
@ -465,11 +435,10 @@ std::optional<std::string> Math::fn_acos(dc_stack_t &stack, Parameters &paramete
// Check whether the entry is a number
if(is_x_num) {
auto val = std::stod(stack.back());
stack.pop_back();
auto val = std::stod(stack.pop(true));
// Push back the result as a string
stack.push_back(trim_digits(acos(val), parameters.precision));
stack.push(trim_digits(acos(val), parameters.precision));
} else {
return "'acos' requires numeric values";
}
@ -477,7 +446,7 @@ std::optional<std::string> Math::fn_acos(dc_stack_t &stack, Parameters &paramete
return std::nullopt;
}
std::optional<std::string> Math::fn_atan(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Math::fn_atan(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'atan' requires one operand";
@ -490,11 +459,10 @@ std::optional<std::string> Math::fn_atan(dc_stack_t &stack, Parameters &paramete
// Check whether the entry is a number
if(is_x_num) {
auto val = std::stod(stack.back());
stack.pop_back();
auto val = std::stod(stack.pop(true));
// Push back the result as a string
stack.push_back(trim_digits(atan(val), parameters.precision));
stack.push(trim_digits(atan(val), parameters.precision));
} else {
return "'atan' requires numeric values";
}
@ -502,7 +470,7 @@ std::optional<std::string> Math::fn_atan(dc_stack_t &stack, Parameters &paramete
return std::nullopt;
}
std::optional<std::string> Math::fn_fact(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Math::fn_fact(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'!' requires one operand";
@ -516,8 +484,7 @@ std::optional<std::string> Math::fn_fact(dc_stack_t &stack, Parameters &paramete
// Check whether the entry is a number
if(is_x_num) {
unsigned long factorial = 1;
auto val = std::stod(stack.back());
stack.pop_back();
auto val = std::stod(stack.pop(true));
if(val == 0.0) {
factorial = 1;
@ -528,7 +495,7 @@ std::optional<std::string> Math::fn_fact(dc_stack_t &stack, Parameters &paramete
}
// Push back the result as a string
stack.push_back(trim_digits(static_cast<double>(factorial), parameters.precision));
stack.push(trim_digits(static_cast<double>(factorial), parameters.precision));
} else {
return "'!' requires numeric values";
}
@ -536,14 +503,14 @@ std::optional<std::string> Math::fn_fact(dc_stack_t &stack, Parameters &paramete
return std::nullopt;
}
std::optional<std::string> Math::fn_pi(dc_stack_t &stack, Parameters &parameters) {
stack.push_back(trim_digits(std::numbers::pi, parameters.precision));
std::optional<std::string> Math::fn_pi(DCStack<std::string> &stack, Parameters &parameters) {
stack.push(trim_digits(std::numbers::pi, parameters.precision));
return std::nullopt;
}
std::optional<std::string> Math::fn_e(dc_stack_t &stack, Parameters &parameters) {
stack.push_back(trim_digits(std::numbers::e, parameters.precision));
std::optional<std::string> Math::fn_e(DCStack<std::string> &stack, Parameters &parameters) {
stack.push(trim_digits(std::numbers::e, parameters.precision));
return std::nullopt;
}

View File

@ -5,27 +5,27 @@
class Math : public IOperation {
public:
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;
std::optional<std::string> exec(DCStack<std::string> &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) override;
private:
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::optional<std::string> fn_add(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_sub(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_mul(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_div(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_mod(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_div_mod(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_mod_exp(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_exp(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_sqrt(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_sin(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_cos(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_tan(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_asin(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_acos(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_atan(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_fact(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_pi(DCStack<std::string> &stack, Parameters &parameters) ;
static std::optional<std::string> fn_e(DCStack<std::string> &stack, Parameters &parameters) ;
static std::string trim_digits(double number, unsigned int precision);
OPType op_type;

View File

@ -1,11 +1,11 @@
#pragma once
#include <optional>
#include "types.h"
#include "adt.h"
class IOperation {
public:
virtual std::optional<std::string> exec(dc_stack_t &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) = 0;
virtual std::optional<std::string> exec(DCStack<std::string> &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) = 0;
virtual ~IOperation() = default;
};

View File

@ -2,10 +2,11 @@
#include <algorithm>
#include <ranges>
#include "adt.cpp"
#include "stack.h"
#include "is_num.h"
std::optional<std::string> Stack::exec(dc_stack_t &stack, Parameters &parameters, __attribute__((unused)) std::unordered_map<char, Register> &regs) {
std::optional<std::string> Stack::exec(DCStack<std::string> &stack, Parameters &parameters, __attribute__((unused)) std::unordered_map<char, Register> &regs) {
std::optional<std::string> err = std::nullopt;
auto print_oradix = [&stack, &parameters, this](radix_base base) {
@ -42,38 +43,38 @@ std::optional<std::string> Stack::exec(dc_stack_t &stack, Parameters &parameters
return err;
}
std::optional<std::string> Stack::fn_print(dc_stack_t &stack, Parameters &parameters, bool new_line) {
std::optional<std::string> Stack::fn_print(DCStack<std::string> &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>(parameters.oradix) != 10 && !is_num<int>(stack.back())) {
if(static_cast<int>(parameters.oradix) != 10 && !is_num<int>(stack.pop(false))) {
return "This output radix requires integer values";
}
switch(parameters.oradix) {
case radix_base::DEC: {
if(new_line) {
std::cout << stack.back() << std::endl;
std::cout << stack.pop(false) << std::endl;
} else {
std::cout << stack.back();
std::cout << stack.pop(false);
}
break;
}
case radix_base::BIN: {
auto head = std::stol(stack.back());
auto head = std::stol(stack.pop(false));
std::cout << to_bin(head) << 'b' << std::endl;
break;
}
case radix_base::OCT: {
auto head = std::stol(stack.back());
auto head = std::stol(stack.pop(false));
std::cout << std::oct << head << 'o' << std::dec << std::endl;
break;
}
case radix_base::HEX: {
auto head = std::stol(stack.back());
auto head = std::stol(stack.pop(false));
std::cout << std::hex << std::uppercase << head << 'h'
<< std::dec << std::nouppercase << std::endl;
break;
@ -84,18 +85,18 @@ std::optional<std::string> Stack::fn_print(dc_stack_t &stack, Parameters &param
return std::nullopt;
}
std::optional<std::string> Stack::fn_pop_head(dc_stack_t &stack) {
std::optional<std::string> Stack::fn_pop_head(DCStack<std::string> &stack) {
// Check if stack is empty
if(stack.empty()) {
return "'R' does not work on empty stack";
}
stack.pop_back();
stack.pop(true);
return std::nullopt;
}
std::optional<std::string> Stack::fn_swap_xy(dc_stack_t &stack) {
std::optional<std::string> Stack::fn_swap_xy(DCStack<std::string> &stack) {
// Check if the stack has enough elements
if(stack.size() < 2) {
return "'r' requires two elements";
@ -111,40 +112,42 @@ std::optional<std::string> Stack::fn_swap_xy(dc_stack_t &stack) {
return std::nullopt;
}
std::optional<std::string> Stack::fn_dup_head(dc_stack_t &stack) {
std::optional<std::string> Stack::fn_dup_head(DCStack<std::string> &stack) {
// Check if the stack has enough elements
if(stack.empty()) {
return "'d' requires one element";
}
auto head = stack.back();
stack.push_back(head);
auto head = stack.pop(false);
stack.push(head);
return std::nullopt;
}
std::optional<std::string> Stack::fn_print_stack(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Stack::fn_print_stack(DCStack<std::string> &stack, Parameters &parameters) {
const auto& const_ref = stack.get_ref();
switch(parameters.oradix) {
case radix_base::DEC: {
for(auto & it : std::ranges::reverse_view(stack)) {
for(auto & it : std::ranges::reverse_view(const_ref)) {
std::cout << it << std::endl;
}
break;
}
case radix_base::BIN: {
for(auto & it : std::ranges::reverse_view(stack)) {
for(auto & it : std::ranges::reverse_view(const_ref)) {
std::cout << to_bin(std::stol(it)) << 'b' << std::endl;
}
break;
}
case radix_base::OCT: {
for(auto & it : std::ranges::reverse_view(stack)) {
for(auto & it : std::ranges::reverse_view(const_ref)) {
std::cout << std::oct << std::stol(it) << 'o' << std::dec << std::endl;
}
break;
}
case radix_base::HEX: {
for(auto & it : std::ranges::reverse_view(stack)) {
for(auto & it : std::ranges::reverse_view(const_ref)) {
std::cout << std::hex << std::uppercase << std::stol(it) << 'h'
<< std::dec << std::nouppercase << std::endl;
}
@ -155,19 +158,19 @@ std::optional<std::string> Stack::fn_print_stack(dc_stack_t &stack, Parameters &
return std::nullopt;
}
std::optional<std::string> Stack::fn_head_size(dc_stack_t &stack) {
std::optional<std::string> Stack::fn_head_size(DCStack<std::string> &stack) {
// Check if the stack has enough elements
if(stack.empty()) {
return "'Z' does not work on empty stack";
}
// Take head of the stack
auto head = stack.back();
auto head = stack.pop(false);
// If it's an integer, count its digits
if(is_num<int>(head)) {
auto num = std::stoi(head);
stack.pop_back();
stack.pop(true);
size_t len = 0;
while(num > 0) {
@ -175,57 +178,57 @@ std::optional<std::string> Stack::fn_head_size(dc_stack_t &stack) {
len++;
}
stack.push_back(std::to_string(len));
stack.push(std::to_string(len));
} else {
// Otherwise, treat the value as a string and count its length
stack.pop_back();
stack.pop(true);
head.erase(std::remove(head.begin(), head.end(), '.'), head.end());
stack.push_back(std::to_string(head.length()));
stack.push(std::to_string(head.length()));
}
return std::nullopt;
}
std::optional<std::string> Stack::fn_stack_size(dc_stack_t &stack) {
stack.push_back(std::to_string(stack.size()));
std::optional<std::string> Stack::fn_stack_size(DCStack<std::string> &stack) {
stack.push(std::to_string(stack.size()));
return std::nullopt;
}
std::optional<std::string> Stack::fn_set_precision(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Stack::fn_set_precision(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'k' requires one operand";
}
// Check whether head is a non-negative number
auto head = stack.back();
auto head = stack.pop(false);
if(!is_num<int>(head) || std::stoi(head) < 0) {
return "Precision must be a non-negative number";
}
// Otherwise extract head of the stack and use it
// to set precision parameter
stack.pop_back();
stack.pop(true);
parameters.precision = std::stoi(head);
return std::nullopt;
}
std::optional<std::string> Stack::fn_get_precision(dc_stack_t &stack, Parameters &parameters) {
stack.push_back(std::to_string(parameters.precision));
std::optional<std::string> Stack::fn_get_precision(DCStack<std::string> &stack, Parameters &parameters) {
stack.push(std::to_string(parameters.precision));
return std::nullopt;
}
std::optional<std::string> Stack::fn_set_oradix(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Stack::fn_set_oradix(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'o' requires one operand";
}
// Check whether the head is a number
auto head = stack.back();
auto head = stack.pop(false);
if(!is_num<int>(head)) {
return "'o' requires numeric values only";
}
@ -243,34 +246,34 @@ std::optional<std::string> Stack::fn_set_oradix(dc_stack_t &stack, Parameters &p
return std::nullopt;
}
std::optional<std::string> Stack::fn_get_oradix(dc_stack_t &stack, Parameters &parameters) {
stack.push_back(std::to_string(static_cast<int>(parameters.oradix)));
std::optional<std::string> Stack::fn_get_oradix(DCStack<std::string> &stack, Parameters &parameters) {
stack.push(std::to_string(static_cast<int>(parameters.oradix)));
return std::nullopt;
}
std::optional<std::string> Stack::fn_set_iradix(dc_stack_t &stack, Parameters &parameters) {
std::optional<std::string> Stack::fn_set_iradix(DCStack<std::string> &stack, Parameters &parameters) {
// Check if stack has enough elements
if(stack.empty()) {
return "'i' requires one operand";
}
// Check whether head is a number within the range 2-16
auto head = stack.back();
auto head = stack.pop(false);
if(!is_num<double>(head) || std::stoi(head) < 2 || std::stoi(head) > 16) {
return "Input base must be a number within the range 2-16(inclusive)";
}
// Otherwise extract head of the stack and use it
// to set input base
stack.pop_back();
stack.pop(true);
parameters.iradix = std::stoi(head);
return std::nullopt;
}
std::optional<std::string> Stack::fn_get_iradix(dc_stack_t &stack, Parameters &parameters) {
stack.push_back(std::to_string(parameters.iradix));
std::optional<std::string> Stack::fn_get_iradix(DCStack<std::string> &stack, Parameters &parameters) {
stack.push(std::to_string(parameters.iradix));
return std::nullopt;
}

View File

@ -5,22 +5,22 @@
class Stack : public IOperation {
public:
explicit Stack(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;
std::optional<std::string> exec(DCStack<std::string> &stack, Parameters &parameters, std::unordered_map<char, Register> &regs) override;
private:
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, 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);
static std::optional<std::string> fn_set_precision(dc_stack_t &stack, Parameters &parameters);
static std::optional<std::string> fn_get_precision(dc_stack_t &stack, Parameters &parameters);
static std::optional<std::string> fn_set_oradix(dc_stack_t &stack, Parameters &parameters);
static std::optional<std::string> fn_get_oradix(dc_stack_t &stack, Parameters &parameters);
static std::optional<std::string> fn_set_iradix(dc_stack_t &stack, Parameters &parameters);
static std::optional<std::string> fn_get_iradix(dc_stack_t &stack, Parameters &parameters);
std::optional<std::string> fn_print(DCStack<std::string> &stack, Parameters &parameters, bool new_line);
static std::optional<std::string> fn_pop_head(DCStack<std::string> &stack);
static std::optional<std::string> fn_swap_xy(DCStack<std::string> &stack);
static std::optional<std::string> fn_dup_head(DCStack<std::string> &stack);
std::optional<std::string> fn_print_stack(DCStack<std::string> &stack, Parameters &parameters);
static std::optional<std::string> fn_head_size(DCStack<std::string> &stack);
static std::optional<std::string> fn_stack_size(DCStack<std::string> &stack);
static std::optional<std::string> fn_set_precision(DCStack<std::string> &stack, Parameters &parameters);
static std::optional<std::string> fn_get_precision(DCStack<std::string> &stack, Parameters &parameters);
static std::optional<std::string> fn_set_oradix(DCStack<std::string> &stack, Parameters &parameters);
static std::optional<std::string> fn_get_oradix(DCStack<std::string> &stack, Parameters &parameters);
static std::optional<std::string> fn_set_iradix(DCStack<std::string> &stack, Parameters &parameters);
static std::optional<std::string> fn_get_iradix(DCStack<std::string> &stack, Parameters &parameters);
constexpr std::string to_bin(auto num);
OPType op_type;

View File

@ -1,18 +0,0 @@
#pragma once
#include <vector>
#include <string>
#include <cstdint>
#include <unordered_map>
using dc_stack_t = std::vector<std::string>;
typedef struct {
dc_stack_t stack;
std::unordered_map<int, std::string> array;
} Register;
enum class radix_base : std::uint8_t { BIN = 2, OCT = 8, DEC = 10, HEX = 16 };
typedef struct {
unsigned int precision;
unsigned short iradix;
radix_base oradix;
} Parameters;