Refactored DC data structure
dc / build (push) Successful in 58s
Details
dc / build (push) Successful in 58s
Details
This commit is contained in:
parent
4b533331f4
commit
aebfec4fb3
|
@ -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)
|
|
@ -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):
|
||||
|
|
4
main.cpp
4
main.cpp
|
@ -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,
|
||||
|
|
|
@ -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})
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
45
src/eval.cpp
45
src/eval.cpp
|
@ -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("]");
|
||||
|
|
|
@ -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> ®s;
|
||||
std::unordered_map<std::string, op_factory_t> op_factory;
|
||||
dc_stack_t &stack;
|
||||
DCStack<std::string> &stack;
|
||||
Parameters ¶meters;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 ¶meters, std::unordered_map<char, Register> ®s) {
|
||||
std::optional<std::string> Macro::exec(DCStack<std::string> &stack, Parameters ¶meters, std::unordered_map<char, Register> ®s) {
|
||||
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 ¶meters
|
|||
return err;
|
||||
}
|
||||
|
||||
std::optional<std::string> Macro::fn_execute(dc_stack_t &stack, Parameters ¶meters, std::unordered_map<char, Register> ®s) {
|
||||
std::optional<std::string> Macro::fn_execute(DCStack<std::string> &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";
|
||||
|
@ -28,9 +29,9 @@ std::optional<std::string> Macro::fn_execute(dc_stack_t &stack, Parameters ¶
|
|||
|
||||
// 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 ¶
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Macro::fn_evaluate_macro(dc_stack_t &stack, Parameters ¶meters, std::unordered_map<char, Register> ®s) {
|
||||
std::optional<std::string> Macro::fn_evaluate_macro(DCStack<std::string> &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";
|
||||
|
@ -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 ¶meters, std::unordered_map<char, Register> ®s) {
|
||||
std::optional<std::string> Macro::fn_read_input(DCStack<std::string> &stack, Parameters ¶meters, std::unordered_map<char, Register> ®s) {
|
||||
// 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();
|
||||
|
|
|
@ -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 ¶meters, std::unordered_map<char, Register> ®s) override;
|
||||
std::optional<std::string> exec(DCStack<std::string> &stack, Parameters ¶meters, std::unordered_map<char, Register> ®s) override;
|
||||
static std::vector<std::string> split(const std::string& str);
|
||||
|
||||
private:
|
||||
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);
|
||||
static std::optional<std::string> fn_execute(DCStack<std::string> &stack, Parameters ¶meters, std::unordered_map<char, Register> ®s);
|
||||
std::optional<std::string> fn_evaluate_macro(DCStack<std::string> &stack, Parameters ¶meters, std::unordered_map<char, Register> ®s);
|
||||
static std::optional<std::string> fn_read_input(DCStack<std::string> &stack, Parameters ¶meters, std::unordered_map<char, Register> ®s);
|
||||
|
||||
OPType op_type;
|
||||
Operator op{};
|
||||
|
|
163
src/math.cpp
163
src/math.cpp
|
@ -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 ¶meters, __attribute__((unused)) std::unordered_map<char, Register> ®s) {
|
||||
std::optional<std::string> Math::exec(DCStack<std::string> &stack, Parameters ¶meters, __attribute__((unused)) std::unordered_map<char, Register> ®s) {
|
||||
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 ¶meters,
|
|||
return err;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_add(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Math::fn_add(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶meter
|
|||
|
||||
// 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 ¶meter
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_sub(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Math::fn_sub(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶meter
|
|||
|
||||
// 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 ¶meter
|
|||
}
|
||||
|
||||
// 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 ¶meter
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_mul(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Math::fn_mul(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶meter
|
|||
|
||||
// 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 ¶meter
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_div(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Math::fn_div(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶meter
|
|||
|
||||
// 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 ¶meter
|
|||
}
|
||||
|
||||
// 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 ¶meter
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_mod(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Math::fn_mod(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶meter
|
|||
|
||||
// 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 ¶meter
|
|||
}
|
||||
|
||||
// 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 ¶meter
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_div_mod(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Math::fn_div_mod(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶m
|
|||
|
||||
// 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 ¶m
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_mod_exp(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Math::fn_mod_exp(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶m
|
|||
// 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 ¶m
|
|||
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 ¶m
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_exp(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Math::fn_exp(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶meter
|
|||
|
||||
// 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 ¶meter
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_sqrt(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Math::fn_sqrt(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶mete
|
|||
|
||||
// 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 ¶mete
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_sin(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Math::fn_sin(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶meter
|
|||
|
||||
// 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 ¶meter
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_cos(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Math::fn_cos(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶meter
|
|||
|
||||
// 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 ¶meter
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_tan(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Math::fn_tan(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶meter
|
|||
|
||||
// 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 ¶meter
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_asin(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Math::fn_asin(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶mete
|
|||
|
||||
// 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 ¶mete
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_acos(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Math::fn_acos(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶mete
|
|||
|
||||
// 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 ¶mete
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_atan(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Math::fn_atan(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶mete
|
|||
|
||||
// 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 ¶mete
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_fact(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Math::fn_fact(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶mete
|
|||
// 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 ¶mete
|
|||
}
|
||||
|
||||
// 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 ¶mete
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_pi(dc_stack_t &stack, Parameters ¶meters) {
|
||||
stack.push_back(trim_digits(std::numbers::pi, parameters.precision));
|
||||
std::optional<std::string> Math::fn_pi(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
stack.push(trim_digits(std::numbers::pi, parameters.precision));
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Math::fn_e(dc_stack_t &stack, Parameters ¶meters) {
|
||||
stack.push_back(trim_digits(std::numbers::e, parameters.precision));
|
||||
std::optional<std::string> Math::fn_e(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
stack.push(trim_digits(std::numbers::e, parameters.precision));
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
38
src/math.h
38
src/math.h
|
@ -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 ¶meters, std::unordered_map<char, Register> ®s) override;
|
||||
std::optional<std::string> exec(DCStack<std::string> &stack, Parameters ¶meters, std::unordered_map<char, Register> ®s) override;
|
||||
|
||||
private:
|
||||
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::optional<std::string> fn_add(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_sub(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_mul(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_div(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_mod(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_div_mod(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_mod_exp(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_exp(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_sqrt(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_sin(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_cos(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_tan(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_asin(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_acos(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_atan(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_fact(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_pi(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::optional<std::string> fn_e(DCStack<std::string> &stack, Parameters ¶meters) ;
|
||||
static std::string trim_digits(double number, unsigned int precision);
|
||||
|
||||
OPType op_type;
|
||||
|
|
|
@ -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 ¶meters, std::unordered_map<char, Register> ®s) = 0;
|
||||
virtual std::optional<std::string> exec(DCStack<std::string> &stack, Parameters ¶meters, std::unordered_map<char, Register> ®s) = 0;
|
||||
virtual ~IOperation() = default;
|
||||
};
|
||||
|
||||
|
|
|
@ -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 ¶meters, __attribute__((unused)) std::unordered_map<char, Register> ®s) {
|
||||
std::optional<std::string> Stack::exec(DCStack<std::string> &stack, Parameters ¶meters, __attribute__((unused)) std::unordered_map<char, Register> ®s) {
|
||||
std::optional<std::string> err = std::nullopt;
|
||||
|
||||
auto print_oradix = [&stack, ¶meters, this](radix_base base) {
|
||||
|
@ -42,38 +43,38 @@ std::optional<std::string> Stack::exec(dc_stack_t &stack, Parameters ¶meters
|
|||
return err;
|
||||
}
|
||||
|
||||
std::optional<std::string> Stack::fn_print(dc_stack_t &stack, Parameters ¶meters, bool new_line) {
|
||||
std::optional<std::string> Stack::fn_print(DCStack<std::string> &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>(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 ¶m
|
|||
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 ¶meters) {
|
||||
std::optional<std::string> Stack::fn_print_stack(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
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 ¶meters) {
|
||||
std::optional<std::string> Stack::fn_set_precision(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
stack.push_back(std::to_string(parameters.precision));
|
||||
std::optional<std::string> Stack::fn_get_precision(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
stack.push(std::to_string(parameters.precision));
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> Stack::fn_set_oradix(dc_stack_t &stack, Parameters ¶meters) {
|
||||
std::optional<std::string> Stack::fn_set_oradix(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
stack.push_back(std::to_string(static_cast<int>(parameters.oradix)));
|
||||
std::optional<std::string> Stack::fn_get_oradix(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
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 ¶meters) {
|
||||
std::optional<std::string> Stack::fn_set_iradix(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
// 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 ¶meters) {
|
||||
stack.push_back(std::to_string(parameters.iradix));
|
||||
std::optional<std::string> Stack::fn_get_iradix(DCStack<std::string> &stack, Parameters ¶meters) {
|
||||
stack.push(std::to_string(parameters.iradix));
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
28
src/stack.h
28
src/stack.h
|
@ -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 ¶meters, std::unordered_map<char, Register> ®s) override;
|
||||
std::optional<std::string> exec(DCStack<std::string> &stack, Parameters ¶meters, std::unordered_map<char, Register> ®s) override;
|
||||
|
||||
private:
|
||||
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, 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);
|
||||
static std::optional<std::string> fn_set_precision(dc_stack_t &stack, Parameters ¶meters);
|
||||
static std::optional<std::string> fn_get_precision(dc_stack_t &stack, Parameters ¶meters);
|
||||
static std::optional<std::string> fn_set_oradix(dc_stack_t &stack, Parameters ¶meters);
|
||||
static std::optional<std::string> fn_get_oradix(dc_stack_t &stack, Parameters ¶meters);
|
||||
static std::optional<std::string> fn_set_iradix(dc_stack_t &stack, Parameters ¶meters);
|
||||
static std::optional<std::string> fn_get_iradix(dc_stack_t &stack, Parameters ¶meters);
|
||||
std::optional<std::string> fn_print(DCStack<std::string> &stack, Parameters ¶meters, 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 ¶meters);
|
||||
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 ¶meters);
|
||||
static std::optional<std::string> fn_get_precision(DCStack<std::string> &stack, Parameters ¶meters);
|
||||
static std::optional<std::string> fn_set_oradix(DCStack<std::string> &stack, Parameters ¶meters);
|
||||
static std::optional<std::string> fn_get_oradix(DCStack<std::string> &stack, Parameters ¶meters);
|
||||
static std::optional<std::string> fn_set_iradix(DCStack<std::string> &stack, Parameters ¶meters);
|
||||
static std::optional<std::string> fn_get_iradix(DCStack<std::string> &stack, Parameters ¶meters);
|
||||
constexpr std::string to_bin(auto num);
|
||||
|
||||
OPType op_type;
|
||||
|
|
18
src/types.h
18
src/types.h
|
@ -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;
|
Loading…
Reference in New Issue