Implement RPN class with evaluation logic, exception handling, and main function; update PmergeMe class to track comparisons and enhance input validation
This commit is contained in:
parent
306e63bd08
commit
08c21e6efe
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
||||
*.d
|
||||
*.o
|
||||
PmergeMe
|
||||
RPN
|
||||
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@ -52,6 +52,8 @@
|
||||
"iomanip": "cpp",
|
||||
"sstream": "cpp",
|
||||
"*.tpp": "cpp",
|
||||
"chrono": "cpp"
|
||||
"chrono": "cpp",
|
||||
"list": "cpp",
|
||||
"ratio": "cpp"
|
||||
}
|
||||
}
|
||||
2
ex01/Makefile
Normal file
2
ex01/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
NAME := RPN
|
||||
include ../common.mk
|
||||
48
ex01/inc/RPN.hpp
Normal file
48
ex01/inc/RPN.hpp
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <stack>
|
||||
|
||||
class RPN
|
||||
{
|
||||
public:
|
||||
RPN();
|
||||
RPN(std::string expression);
|
||||
RPN(const RPN &other);
|
||||
~RPN();
|
||||
RPN &operator=(const RPN &other);
|
||||
void setExpression(std::string expression);
|
||||
int evaluate();
|
||||
|
||||
class NoExpressionException : public std::exception
|
||||
{
|
||||
public:
|
||||
const char *what() const noexcept override;
|
||||
};
|
||||
|
||||
class InvalidExpressionException : public std::exception
|
||||
{
|
||||
public:
|
||||
const char *what() const noexcept override;
|
||||
};
|
||||
|
||||
class DivisionByZeroException : public std::exception
|
||||
{
|
||||
public:
|
||||
const char *what() const noexcept override;
|
||||
};
|
||||
|
||||
class InvalidCharacterException : public std::exception
|
||||
{
|
||||
public:
|
||||
const char *what() const noexcept override;
|
||||
};
|
||||
|
||||
private:
|
||||
std::string _expression;
|
||||
|
||||
bool isWellformed() const;
|
||||
bool isOperator(char c) const;
|
||||
int applyOperator(int a, int b, char op) const;
|
||||
void printStack(std::stack<int> stack) const;
|
||||
};
|
||||
172
ex01/src/RPN.cpp
Normal file
172
ex01/src/RPN.cpp
Normal file
@ -0,0 +1,172 @@
|
||||
#include "RPN.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <stack>
|
||||
#include <iostream>
|
||||
|
||||
RPN::RPN() : _expression("")
|
||||
{
|
||||
}
|
||||
|
||||
RPN::RPN(std::string expression) : _expression(expression)
|
||||
{
|
||||
}
|
||||
|
||||
RPN::RPN(const RPN &other) : _expression(other._expression)
|
||||
{
|
||||
}
|
||||
|
||||
RPN::~RPN()
|
||||
{
|
||||
}
|
||||
|
||||
RPN &RPN::operator=(const RPN &other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
_expression = other._expression;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void RPN::setExpression(std::string expression)
|
||||
{
|
||||
_expression = expression;
|
||||
}
|
||||
|
||||
int RPN::evaluate()
|
||||
{
|
||||
if (_expression.empty())
|
||||
throw RPN::NoExpressionException();
|
||||
if (!isWellformed())
|
||||
throw RPN::InvalidExpressionException();
|
||||
std::stack<int> stack;
|
||||
for (char c : _expression)
|
||||
{
|
||||
if (std::isspace(c))
|
||||
continue;
|
||||
if (std::isdigit(c))
|
||||
stack.push(c - '0');
|
||||
else if (isOperator(c))
|
||||
{
|
||||
if (stack.size() < 2)
|
||||
throw RPN::InvalidExpressionException();
|
||||
|
||||
int b = stack.top();
|
||||
stack.pop();
|
||||
int a = stack.top();
|
||||
stack.pop();
|
||||
int result = applyOperator(a, b, c);
|
||||
stack.push(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw RPN::InvalidCharacterException();
|
||||
}
|
||||
// std::cout << "Stack after processing '" << c << "': ";
|
||||
// printStack(stack);
|
||||
}
|
||||
if (stack.size() != 1)
|
||||
throw RPN::InvalidExpressionException();
|
||||
return stack.top();
|
||||
}
|
||||
|
||||
bool RPN::isWellformed() const
|
||||
{
|
||||
bool needs_space = false;
|
||||
for (char c : _expression)
|
||||
{
|
||||
if (std::isspace(c))
|
||||
{
|
||||
if (needs_space)
|
||||
needs_space = false;
|
||||
continue;
|
||||
}
|
||||
if (std::isdigit(c) || isOperator(c))
|
||||
{
|
||||
if (needs_space)
|
||||
return false;
|
||||
needs_space = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RPN::isOperator(char c) const
|
||||
{
|
||||
if (std::string("+-*/").find(c) != std::string::npos)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int RPN::applyOperator(int a, int b, char op) const
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case '+':
|
||||
return a + b;
|
||||
case '-':
|
||||
return a - b;
|
||||
case '*':
|
||||
return a * b;
|
||||
case '/':
|
||||
if (b == 0)
|
||||
throw RPN::DivisionByZeroException();
|
||||
return a / b;
|
||||
default:
|
||||
throw RPN::InvalidExpressionException();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RPN::printStack(std::stack<int> stack) const
|
||||
{
|
||||
if (stack.empty())
|
||||
{
|
||||
std::cout << "[]\n";
|
||||
return;
|
||||
}
|
||||
|
||||
std::stack<int> temp;
|
||||
while (!stack.empty())
|
||||
{
|
||||
temp.push(stack.top());
|
||||
stack.pop();
|
||||
}
|
||||
|
||||
std::cout << "[";
|
||||
while (!temp.empty())
|
||||
{
|
||||
std::cout << temp.top();
|
||||
temp.pop();
|
||||
if (!temp.empty())
|
||||
std::cout << ", ";
|
||||
}
|
||||
std::cout << "]\n";
|
||||
}
|
||||
|
||||
const char *RPN::NoExpressionException::NoExpressionException::what() const noexcept
|
||||
{
|
||||
return "No expression provided.";
|
||||
}
|
||||
|
||||
const char *RPN::InvalidExpressionException::InvalidExpressionException::what() const noexcept
|
||||
{
|
||||
return "Invalid RPN expression.";
|
||||
}
|
||||
|
||||
const char *RPN::DivisionByZeroException::DivisionByZeroException::what() const noexcept
|
||||
{
|
||||
return "Division by zero.";
|
||||
}
|
||||
|
||||
const char *RPN::InvalidCharacterException::InvalidCharacterException::what() const noexcept
|
||||
{
|
||||
return "Invalid character in expression.";
|
||||
}
|
||||
25
ex01/src/main.cpp
Normal file
25
ex01/src/main.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "RPN.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
std::cerr << "Usage: " << argv[0] << " <RPN expression>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
RPN rpn(argv[1]);
|
||||
int result = rpn.evaluate();
|
||||
std::cout << result << std::endl;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -18,6 +18,7 @@ public:
|
||||
|
||||
void sort();
|
||||
std::string getString() const;
|
||||
int getComparisons() const;
|
||||
|
||||
private:
|
||||
Container _data;
|
||||
|
||||
@ -13,11 +13,13 @@
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
|
||||
template <typename T>
|
||||
std::string getTypeName() {
|
||||
if (std::is_same_v<T, std::vector<int>>) return "std::vector<int> ";
|
||||
if (std::is_same_v<T, std::deque<int>>) return "std::deque<int> ";
|
||||
std::string getTypeName()
|
||||
{
|
||||
if (std::is_same_v<T, std::vector<int>>)
|
||||
return "std::vector<int> ";
|
||||
if (std::is_same_v<T, std::deque<int>>)
|
||||
return "std::deque<int> ";
|
||||
return typeid(T).name(); // fallback to mangled name
|
||||
}
|
||||
|
||||
@ -27,6 +29,8 @@ PmergeMe<Container>::PmergeMe(const int argc, const char **argv) : _comparisons(
|
||||
for (int i = 1; argv[i] != nullptr; ++i)
|
||||
{
|
||||
size_t pos;
|
||||
try
|
||||
{
|
||||
int value = std::stoi(argv[i], &pos);
|
||||
if (value < 0)
|
||||
throw std::invalid_argument("All inputs must be non-negative integers");
|
||||
@ -35,6 +39,15 @@ PmergeMe<Container>::PmergeMe(const int argc, const char **argv) : _comparisons(
|
||||
|
||||
_data.push_back(value);
|
||||
}
|
||||
catch (const std::out_of_range &e)
|
||||
{
|
||||
throw std::out_of_range("Input value out of range");
|
||||
}
|
||||
catch (const std::invalid_argument &e)
|
||||
{
|
||||
throw std::invalid_argument("Invalid input: not a valid integer");
|
||||
}
|
||||
}
|
||||
|
||||
if (!areAllUnique())
|
||||
throw std::invalid_argument("All inputs must be unique integers");
|
||||
@ -93,6 +106,12 @@ std::string PmergeMe<Container>::getString() const
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
int PmergeMe<Container>::getComparisons() const
|
||||
{
|
||||
return _comparisons;
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
bool PmergeMe<Container>::less(int a, int b)
|
||||
{
|
||||
@ -198,4 +217,3 @@ std::ostream &operator<<(std::ostream &os, const PmergeMe<Container> &obj)
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
#include "PmergeMe.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const std::vector<int> &obj)
|
||||
{
|
||||
for (std::vector<int>::const_iterator it = obj.begin(); it != obj.end(); ++it)
|
||||
{
|
||||
if (it != obj.begin())
|
||||
os << " ";
|
||||
os << *it;
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -10,12 +10,14 @@ int main(const int argc, const char **argv)
|
||||
|
||||
try
|
||||
{
|
||||
PmergeMe<std::vector<int> > sorter(argc, argv);
|
||||
std::cout << "Before: " << sorter << std::endl;
|
||||
sorter.sort();
|
||||
PmergeMe<std::vector<int> > sorter_vector(argc, argv);
|
||||
std::cout << "Before: " << sorter_vector << std::endl;
|
||||
sorter_vector.sort();
|
||||
PmergeMe<std::deque<int> > sorter_deque(argc, argv);
|
||||
sorter_deque.sort();
|
||||
std::cout << "After: " << sorter_deque << std::endl;
|
||||
std::cout << "Total comparisons (vector): " << sorter_vector.getComparisons() << std::endl;
|
||||
std::cout << "Total comparisons (deque): " << sorter_deque.getComparisons() << std::endl;
|
||||
|
||||
}
|
||||
catch (const std::invalid_argument &e)
|
||||
@ -23,6 +25,16 @@ int main(const int argc, const char **argv)
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (const std::out_of_range &e)
|
||||
{
|
||||
std::cerr << "Error: "<< e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "Unexpected error: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user