From 8798ee646df00d07974e7979dbdbb4edab8441e1 Mon Sep 17 00:00:00 2001 From: tovjemam Date: Thu, 4 Dec 2025 11:30:41 +0100 Subject: [PATCH] Add terminal --- src/main.cpp | 4 ++ src/mp/lib.hpp | 2 +- src/term/mpterm.hpp | 169 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 src/term/mpterm.hpp diff --git a/src/main.cpp b/src/main.cpp index 42d154a..b7b333e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,7 @@ #include #include "mp/mp.hpp" +#include "term/mpterm.hpp" template static void PrintInt(const char* name, const T& val) @@ -181,4 +182,7 @@ int main() } } + MpTerm term; + term.run(); + } \ No newline at end of file diff --git a/src/mp/lib.hpp b/src/mp/lib.hpp index cbb0c89..8596a20 100644 --- a/src/mp/lib.hpp +++ b/src/mp/lib.hpp @@ -101,7 +101,7 @@ inline T factorial(const T& n) } T result = 1; - for (T i = 2; i <= n; ++i) + for (T i = 2; i <= n; i += 1) { result *= i; } diff --git a/src/term/mpterm.hpp b/src/term/mpterm.hpp new file mode 100644 index 0000000..2d6ba56 --- /dev/null +++ b/src/term/mpterm.hpp @@ -0,0 +1,169 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "mp/int.hpp" +#include "mp/lib.hpp" +#include "mp/math.hpp" + +template +class MpTerm +{ +public: + using MyInt = mp::Int; + + MpTerm() = default; + + void run() + { + const std::regex bin_op_regex(R"(^\s*([\-\+]?\d+|\$\d)\s*([\+\-\/\*])\s*([\-\+]?\d+|\$\d)\s*$)"); + const std::regex un_op_regex(R"(^\s*([\-\+]?\d+|\$\d)\s*([\!])\s*$)"); + + while (true) + { + std::cout << "> "; + std::string line; + if (!std::getline(std::cin, line)) + break; + + if (line == "exit" || line == "quit") + break; + + if (line == "bank") + { + print_history(); + continue; + } + + std::smatch match; + + if (std::regex_match(line, match, bin_op_regex)) + { + binary_op(match[1], match[3], match[2].str()[0]); + } + else if (std::regex_match(line, match, un_op_regex)) + { + if (match[2].str() == "!") + { + factorial(match[1]); + } + else + { + std::cout << "Unknown unary operator." << std::endl; + } + } + else + { + std::cout << "Invalid command format." << std::endl; + } + } + } + +private: + void binary_op(const std::string& lhs_str, const std::string& rhs_str, char op) + { + MyInt lhs = parse_operand(lhs_str); + MyInt rhs = parse_operand(rhs_str); + + MyInt result; + + try + { + switch (op) + { + case '+': + result = lhs + rhs; + break; + case '-': + result = lhs - rhs; + break; + case '*': + result = lhs * rhs; + break; + case '/': + result = lhs / rhs; + break; + default: + throw std::invalid_argument("Unknown operator"); + } + + output(result); + } + catch (const mp::OverflowErrorOf& e) + { + std::cout << "Warning: Result overflew" << std::endl; + output(e.value()); + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << std::endl; + } + + } + + void factorial(const std::string& operand_str) + { + MyInt operand = parse_operand(operand_str); + + try + { + output(mp::factorial(operand)); + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << std::endl; + } + } + + void output(const MyInt& value) + { + m_history[m_next] = value; + m_next = (m_next + 1) % HISTORY; + print_var(1); + } + + MyInt parse_operand(const std::string& token) + { + if (token.size() > 0 && token[0] == '$') + { + size_t idx = std::stoul(token.substr(1)); + return m_history[get_memory_idx(idx)]; + } + else + { + return mp::from_string(token.c_str()); + } + } + + void print_history() const + { + for (size_t i = 1; i <= HISTORY; ++i) + { + print_var(i); + } + } + + void print_var(size_t num) const + { + std::cout << '$' << num << " = " << mp::to_string(m_history[get_memory_idx(num)]) << std::endl; + } + + size_t get_memory_idx(size_t num) const + { + if (num == 0 || num > HISTORY) + { + throw std::out_of_range("Memory index out of range"); + } + return (m_next + HISTORY - num) % HISTORY; + } + +private: + static constexpr size_t HISTORY = 5; + + std::array m_history; + size_t m_next = 0; +}; \ No newline at end of file