From 429896d153a11fe818b451e7f237c7c0c98daec3 Mon Sep 17 00:00:00 2001 From: Raphael Date: Sun, 27 Apr 2025 18:53:22 +0200 Subject: [PATCH] feat(09): finishing the exercice 01 --- cpp09/ex01/Makefile | 34 +++++++++++- cpp09/ex01/RPN.hpp | 17 +++++- cpp09/ex01/main.cpp | 131 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 163 insertions(+), 19 deletions(-) diff --git a/cpp09/ex01/Makefile b/cpp09/ex01/Makefile index 32e6fe5..8b6e1f2 100644 --- a/cpp09/ex01/Makefile +++ b/cpp09/ex01/Makefile @@ -6,7 +6,7 @@ # By: rparodi +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2023/11/12 11:05:05 by rparodi #+# #+# # -# Updated: 2025/04/27 13:01:07 by rparodi ### ########.fr # +# Updated: 2025/04/27 18:52:30 by rparodi ### ########.fr # # # # **************************************************************************** # @@ -83,6 +83,38 @@ $(OBJDIRNAME)/%.o: %.cpp @printf '$(GREY) Compiling $(END)$(GREEN)$<$(END)\n' @$(CXX) $(CXXFLAGS) -o $@ -c $< +test: + @printf '$(GREY) Testing with $(END)$(GOLD)./RPN ""$(END)\n' + @./$(NAME) "" + @printf '\n' + @printf '$(GREY) MemCheck with $(END)$(GOLD)./RPN ""$(END)\n' + @valgrind ./$(NAME) "" 2> /tmp/RPN_test + @cat /tmp/RPN_test | rg --color=always "ERROR SUMMARY" -A 10 + @printf '$(GREY) Testing with $(END)$(GOLD)./RPN "8 9 * 9 - 9 - 9 - 4 - 1 +"$(END)\n' + @./$(NAME) "8 9 * 9 - 9 - 9 - 4 - 1 +" + @printf '\n' + @printf '$(GREY) MemCheck with $(END)$(GOLD)./RPN "8 9 * 9 - 9 - 9 - 4 - 1 +"$(END)\n' + @valgrind ./$(NAME) "8 9 * 9 - 9 - 9 - 4 - 1 +" 2> /tmp/RPN_test + @cat /tmp/RPN_test | rg --color=always "ERROR SUMMARY" -A 10 + @printf '$(GREY) Testing with $(END)$(GOLD)./RPN "7 7 * 7 -"$(END)\n' + @./$(NAME) "7 7 * 7 -" + @printf '\n' + @printf '$(GREY) MemCheck with $(END)$(GOLD)./RPN "7 7 * 7 -"$(END)\n' + @valgrind ./$(NAME) "7 7 * 7 -" 2> /tmp/RPN_test + @cat /tmp/RPN_test | rg --color=always "ERROR SUMMARY" -A 10 + @printf '$(GREY) Testing with $(END)$(GOLD)./RPN "1 2 * 2 / 2 * 2 4 - +"$(END)\n' + @./$(NAME) "1 2 * 2 / 2 * 2 4 - +" + @printf '\n' + @printf '$(GREY) MemCheck with $(END)$(GOLD)./RPN "1 2 * 2 / 2 * 2 4 - +"$(END)\n' + @valgrind ./$(NAME) "1 2 * 2 / 2 * 2 4 - +" 2> /tmp/RPN_test + @cat /tmp/RPN_test | rg --color=always "ERROR SUMMARY" -A 10 + @printf '$(GREY) Testing with $(END)$(GOLD)./RPN "(1 + 1)"$(END)\n' + @./$(NAME) "(1 + 1)" + @printf '\n' + @printf '$(GREY) MemCheck with $(END)$(GOLD)./RPN "(1 + 1)"$(END)\n' + @valgrind ./$(NAME) "(1 + 1)" 2> /tmp/RPN_test + @cat /tmp/RPN_test | rg --color=always "ERROR SUMMARY" -A 10 + # Header header: @clear diff --git a/cpp09/ex01/RPN.hpp b/cpp09/ex01/RPN.hpp index 97ab1fb..2f0a436 100644 --- a/cpp09/ex01/RPN.hpp +++ b/cpp09/ex01/RPN.hpp @@ -6,7 +6,7 @@ /* By: rparodi +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/04/27 13:03:08 by rparodi #+# #+# */ -/* Updated: 2025/04/27 15:39:50 by rparodi ### ########.fr */ +/* Updated: 2025/04/27 17:13:10 by rparodi ### ########.fr */ /* */ /* ************************************************************************** */ @@ -24,3 +24,18 @@ #define CLR_WHITE "\033[0;37m" #define CLR_GOLD "\033[38;5;220m" #define CLR_GREY "\033[38;5;240m" + +enum e_op +{ + NUM = 0, + ADD, + SUB, + MUL, + DIV +}; + +typedef struct s_tok +{ + e_op type; + int value; +} tok; diff --git a/cpp09/ex01/main.cpp b/cpp09/ex01/main.cpp index 9c8b82e..bc86ad0 100644 --- a/cpp09/ex01/main.cpp +++ b/cpp09/ex01/main.cpp @@ -1,24 +1,16 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* main.cpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: rparodi +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2025/04/27 12:58:08 by rparodi #+# #+# */ -/* Updated: 2025/04/27 15:50:20 by rparodi ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#include -#include #include "RPN.hpp" +#include +#include +#include +#include +#include +#include /** - * @brief check if the input have only numbers and operators + * @brief Check if the input string is valid * - * @param str the input of the user - * @return true if the input is valid, false otherwise + * @param str input of the user + * @return true if the input is valid */ bool check_input(std::string str) { std::string allowed = "0123456789 +-*/"; @@ -29,12 +21,117 @@ bool check_input(std::string str) { return true; } +/** + * @brief split the input string into a list of tokens + * + * @param input input of the user (already checked) + * @return std::list list of tokens + */ +std::list split_to_list(const std::string& input) { + std::istringstream iss(input); + std::string token; + std::list tokens; + e_op op; + int tmp; + + while (iss >> token) { + op = NUM; + tmp = 0; + if (token == "*") { + op = MUL; + } + else if (token == "/") { + op = DIV; + } + else if (token == "+") { + op = ADD; + } + else if (token == "-") { + op = SUB; + } + else { + op = NUM; + tmp = std::strtol(token.c_str(), 0, 10); + } + tok to_push = {op, tmp}; + tokens.push_back(to_push); + } + return tokens; +} + +/** + * @brief Execute the RPN algorithm + * + * @param tokens list of tokens + * @return true if the execution was successful + */ +bool exec_rpn(std::list tokens) { + if (tokens.size() < 3) { + std::cerr << CLR_RED << "Error:\tNot enough operands" << CLR_RESET << std::endl; + return false; + } + + std::list numbers; + + while (!tokens.empty()) { + tok current = tokens.front(); + tokens.pop_front(); + + if (current.type == NUM) { + numbers.push_back(current.value); + } + else if (current.type == ADD || current.type == SUB || current.type == MUL || current.type == DIV) { + if (numbers.size() < 2) { + std::cerr << CLR_RED << "Error:\tNot enough operands for operator" << CLR_RESET << std::endl; + return false; + } + + int b = numbers.back(); + numbers.pop_back(); + int a = numbers.back(); + numbers.pop_back(); + + if (current.type == ADD) + numbers.push_back(a + b); + else if (current.type == SUB) + numbers.push_back(a - b); + else if (current.type == MUL) + numbers.push_back(a * b); + else if (current.type == DIV) { + if (b == 0) { + std::cerr << CLR_RED << "Error:\tDivision by zero" << CLR_RESET << std::endl; + return false; + } + numbers.push_back(a / b); + } + } + else { + std::cerr << CLR_RED << "Error:\tInvalid token" << CLR_RESET << std::endl; + return false; + } + } + + if (numbers.size() != 1) { + std::cerr << CLR_RED << "Error:\tInvalid final stack state" << CLR_RESET << std::endl; + return false; + } + + std::cout << CLR_GREEN << "Result:\t" << numbers.back() << CLR_RESET << std::endl; + return true; +} + int main(int argc, char **argv) { if (argc != 2) { std::cerr << CLR_RED << "Usage:\t" << argv[0] << " " << CLR_RESET << std::endl; + return 1; } std::string input = argv[1]; if (!check_input(input)) { std::cerr << CLR_RED << "Error:\tYour input can only have digits, spaces and the operators '+' '-' '*' '/'" << CLR_RESET << std::endl; + return 1; + } else { + std::list tokens = split_to_list(input); + exec_rpn(tokens); } } +