RPN.cpp
1 /* ************************************************************************** */ 2 /* */ 3 /* ::: :::::::: */ 4 /* RPN.cpp :+: :+: :+: */ 5 /* +:+ +:+ +:+ */ 6 /* By: gychoi <gychoi@student.42seoul.kr> +#+ +:+ +#+ */ 7 /* +#+#+#+#+#+ +#+ */ 8 /* Created: 2024/01/10 22:01:14 by gychoi #+# #+# */ 9 /* Updated: 2024/01/16 15:40:42 by gychoi ### ########.fr */ 10 /* */ 11 /* ************************************************************************** */ 12 13 #include "RPN.hpp" 14 15 std::stack<int, std::list<int> > RPN::sStack; 16 17 static void _calculate(std::stack<int, std::list<int> >& s, char const& oprt); 18 static int _popOperand(std::stack<int, std::list<int> >& s); 19 static bool _isValidToken(std::string const& token); 20 static bool _isOperator(char const& ch); 21 22 /* ************************************************************************** */ 23 /* Constructor & Destructor */ 24 /* ************************************************************************** */ 25 26 RPN::RPN() 27 { 28 // nothing to do 29 } 30 31 RPN::RPN(__attribute__((unused)) RPN const& other) 32 { 33 // nothing to do 34 } 35 36 RPN& RPN::operator=(__attribute__((unused)) RPN const& other) 37 { 38 return *this; 39 } 40 41 RPN::~RPN() 42 { 43 // nothing to do 44 } 45 46 /* ************************************************************************** */ 47 /* Public Member Function */ 48 /* ************************************************************************** */ 49 50 int RPN::execute(char* expr) 51 { 52 std::istringstream iss(expr); 53 std::string token; 54 55 while (std::getline(iss, token, ' ')) 56 { 57 if (iss.fail()) 58 { 59 throw std::runtime_error("Failed to read string stream"); 60 } 61 else if (!_isValidToken(token)) 62 { 63 throw std::invalid_argument("Invalid argument: " + token); 64 } 65 else 66 { 67 if (token.length() == 1 && _isOperator(token[0])) 68 { 69 _calculate(sStack, token[0]); 70 } 71 else 72 { 73 sStack.push(std::atoi(token.c_str())); 74 } 75 } 76 } 77 78 if (sStack.size() != 1) 79 { 80 throw std::runtime_error("Malformed expression"); 81 } 82 else 83 { 84 // good! 85 } 86 87 return sStack.top(); 88 } 89 90 /* ************************************************************************** */ 91 /* Utility Function */ 92 /* ************************************************************************** */ 93 94 static void _calculate(std::stack<int, std::list<int> >& s, char const& oprt) 95 { 96 if (s.size() < 2) 97 { 98 throw std::runtime_error("Malformed expression"); 99 } 100 else 101 { 102 // ready to calculate 103 } 104 105 int opd2 = _popOperand(s); 106 int opd1 = _popOperand(s); 107 108 switch (oprt) 109 { 110 case '+': 111 s.push(opd1 + opd2); 112 break; 113 case '-': 114 s.push(opd1 - opd2); 115 break; 116 case '*': 117 s.push(opd1 * opd2); 118 break; 119 case '/': 120 { 121 if (opd2 == 0) 122 { 123 throw std::runtime_error("Division by zero"); 124 } 125 else 126 { 127 s.push(opd1 / opd2); 128 } 129 break; 130 } 131 default: 132 // unreachable 133 std::logic_error("Debugger ON..."); 134 } 135 } 136 137 static int _popOperand(std::stack<int, std::list<int> >& s) 138 { 139 int op = s.top(); 140 141 s.pop(); 142 return op; 143 } 144 145 static bool _isValidToken(std::string const& token) 146 { 147 if (token.length() == 1 && _isOperator(token[0])) 148 { 149 return true; 150 } 151 else if (token.length() == 1 && std::isdigit(token[0])) 152 { 153 return true; 154 } 155 else if (token.length() == 2 && token[0] == '+' && std::isdigit(token[1])) 156 { 157 return true; 158 } 159 else if (token.length() == 2 && token[0] == '-' && std::isdigit(token[1])) 160 { 161 return true; 162 } 163 else 164 { 165 // invalid input 166 } 167 return false; 168 } 169 170 static bool _isOperator(char const& ch) 171 { 172 return ch == '+' || ch == '-' || ch == '*' || ch == '/'; 173 }