Add terminal

This commit is contained in:
tovjemam 2025-12-04 11:30:41 +01:00
parent e6a6de048d
commit 8798ee646d
3 changed files with 174 additions and 1 deletions

View File

@ -2,6 +2,7 @@
#include <iostream>
#include "mp/mp.hpp"
#include "term/mpterm.hpp"
template <class T>
static void PrintInt(const char* name, const T& val)
@ -181,4 +182,7 @@ int main()
}
}
MpTerm<mp::UNLIMITED> term;
term.run();
}

View File

@ -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;
}

169
src/term/mpterm.hpp Normal file
View File

@ -0,0 +1,169 @@
#pragma once
#include <array>
#include <cstddef>
#include <iostream>
#include <regex>
#include <string>
#include "mp/int.hpp"
#include "mp/lib.hpp"
#include "mp/math.hpp"
template <size_t Size>
class MpTerm
{
public:
using MyInt = mp::Int<Size>;
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<MyInt, MyInt>& 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<Size>(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<MyInt, HISTORY> m_history;
size_t m_next = 0;
};