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  }