Add terminal
This commit is contained in:
parent
e6a6de048d
commit
8798ee646d
@ -2,6 +2,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "mp/mp.hpp"
|
#include "mp/mp.hpp"
|
||||||
|
#include "term/mpterm.hpp"
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
static void PrintInt(const char* name, const T& val)
|
static void PrintInt(const char* name, const T& val)
|
||||||
@ -181,4 +182,7 @@ int main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MpTerm<mp::UNLIMITED> term;
|
||||||
|
term.run();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ inline T factorial(const T& n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
T result = 1;
|
T result = 1;
|
||||||
for (T i = 2; i <= n; ++i)
|
for (T i = 2; i <= n; i += 1)
|
||||||
{
|
{
|
||||||
result *= i;
|
result *= i;
|
||||||
}
|
}
|
||||||
|
|||||||
169
src/term/mpterm.hpp
Normal file
169
src/term/mpterm.hpp
Normal 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;
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user