From d5746c68a253adf0728976cd9c8179c60b367a60 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Sat, 19 Oct 2024 03:06:20 +0300 Subject: [PATCH 1/7] Homework 5 task 2 --- homework_5/CMakeLists.txt | 2 + homework_5/task_2/CMakeLists.txt | 11 ++++ homework_5/task_2/main.c | 71 +++++++++++++++++++++ homework_5/task_2/postfixCalc.c | 90 +++++++++++++++++++++++++++ homework_5/task_2/postfixCalc.h | 26 ++++++++ homework_5/task_2/test.c | 102 +++++++++++++++++++++++++++++++ 6 files changed, 302 insertions(+) create mode 100644 homework_5/task_2/CMakeLists.txt create mode 100644 homework_5/task_2/main.c create mode 100644 homework_5/task_2/postfixCalc.c create mode 100644 homework_5/task_2/postfixCalc.h create mode 100644 homework_5/task_2/test.c diff --git a/homework_5/CMakeLists.txt b/homework_5/CMakeLists.txt index dc70726..f43573e 100644 --- a/homework_5/CMakeLists.txt +++ b/homework_5/CMakeLists.txt @@ -3,3 +3,5 @@ project(homework_5) set(homeworkName "${PROJECT_NAME}") add_subdirectory(stack) + +add_subdirectory(task_2) diff --git a/homework_5/task_2/CMakeLists.txt b/homework_5/task_2/CMakeLists.txt new file mode 100644 index 0000000..a625d7e --- /dev/null +++ b/homework_5/task_2/CMakeLists.txt @@ -0,0 +1,11 @@ +project("${homeworkName}_task_2") + +add_library(postfixCalc postfixCalc.c) + +add_executable(${PROJECT_NAME} main.c) +target_link_libraries(${PROJECT_NAME} postfixCalc) +target_link_libraries(${PROJECT_NAME} stack) + +add_executable(${PROJECT_NAME}_test test.c) +target_link_libraries(${PROJECT_NAME}_test postfixCalc) +target_link_libraries(${PROJECT_NAME}_test stack) \ No newline at end of file diff --git a/homework_5/task_2/main.c b/homework_5/task_2/main.c new file mode 100644 index 0000000..4e24b41 --- /dev/null +++ b/homework_5/task_2/main.c @@ -0,0 +1,71 @@ +#include + +#include "postfixCalc.h" + +bool readAndEvaluate(PostfixCalc *calc) { + printf("input digits and operands (allowed characters: 0123456789+-*/) (you can use space to split them):\n"); + printf(" > "); + + while (true) { + char input = getchar(); + if (input == EOF || input == '\n') { + break; + } + + if (input == ' ') { + continue; + } + + switch (calcConsumeInput(calc, input)) + { + case CALC_CONSUME_OK: + break; + case CALC_CONSUME_ALLOCATION_ERROR: + printf("allocation error\n"); + return false; + + case CALC_CONSUME_NOT_ENOUGH_OPERANDS: + printf("not enough operands to perform operation '%c'\n", input); + return false; + + case CALC_CONSUME_UNKNOWN_INPUT: + printf("unknown character: '%c'\n", input); + return false; + } + } + + int result = 0; + + switch (calcTryGetResult(calc, &result)) + { + case CALC_GET_RESULT_OK: + printf("evaluation result: %d\n", result); + break; + + case CALC_IS_EMPTY_BEFORE_READ: + printf("nothing to evaluate\n"); + return false; + + case CALC_NOT_EMPTY_AFTER_READ: + printf("not all numbers are used\n"); + return false; + } + + return true; +} + +int main(void) { + PostfixCalc *calc; + + if (!calcCreate(&calc)) { + printf("allocation failed"); + return 1; + } + + if (!readAndEvaluate(calc)) { + calcDispose(calc); + return 1; + } + + calcDispose(calc); +} diff --git a/homework_5/task_2/postfixCalc.c b/homework_5/task_2/postfixCalc.c new file mode 100644 index 0000000..bed6f8e --- /dev/null +++ b/homework_5/task_2/postfixCalc.c @@ -0,0 +1,90 @@ +#include "postfixCalc.h" + +#include + +#include "../stack/stack.h" + +typedef struct PostfixCalc { + Stack *stack; +} PostfixCalc; + +bool calcCreate(PostfixCalc **calc) { + *calc = malloc(sizeof(PostfixCalc)); + if (calc == NULL) { + return false; + } + + if (!stackCreate(&(*calc)->stack)) { + return false; + } + + return true; +} + +CalcConsumeResult calcConsumeInput(PostfixCalc *calc, char input) { + switch (input) + { + case '+': + case '-': + case '*': + case '/': + uint64_t valueA = -1; + if (!stackTryPop(calc->stack, &valueA)) { + return CALC_CONSUME_NOT_ENOUGH_OPERANDS; + } + + uint64_t valueB = -1; + if (!stackTryPop(calc->stack, &valueB)) { + return CALC_CONSUME_NOT_ENOUGH_OPERANDS; + } + + int left = (int)valueB; + int right = (int)valueA; + + int value = 0; + if (input == '+') { + value = left + right; + } else if (input == '-') { + value = left - right; + } else if (input == '*') { + value = left * right; + } else if (input == '/') { + value = left / right; + } + + if (!stackPush(calc->stack, (uint64_t)value)) { + return CALC_CONSUME_ALLOCATION_ERROR; + } + + break; + + default: + if (input >= '0' && input <= '9') { + uint64_t value = input - '0'; + if (!stackPush(calc->stack, value)) { + return CALC_CONSUME_ALLOCATION_ERROR; + } + } else { + return CALC_CONSUME_UNKNOWN_INPUT; + } + + break; + } + + return CALC_CONSUME_OK; +} + +CalcGetResultResult calcTryGetResult(PostfixCalc *calc, int *result) { + uint64_t value = 0; + if (!stackTryPop(calc->stack, &value)) { + return CALC_IS_EMPTY_BEFORE_READ; + } + + *result = (int)value; + return stackIsEmpty(calc->stack) ? CALC_GET_RESULT_OK : CALC_NOT_EMPTY_AFTER_READ; +} + +void calcDispose(PostfixCalc *calc) { + stackDispose(calc->stack); + free(calc); +} diff --git a/homework_5/task_2/postfixCalc.h b/homework_5/task_2/postfixCalc.h new file mode 100644 index 0000000..6e59905 --- /dev/null +++ b/homework_5/task_2/postfixCalc.h @@ -0,0 +1,26 @@ +#pragma once + +#include "stdbool.h" + +typedef struct PostfixCalc PostfixCalc; + +typedef enum { + CALC_CONSUME_OK, + CALC_CONSUME_NOT_ENOUGH_OPERANDS, + CALC_CONSUME_ALLOCATION_ERROR, + CALC_CONSUME_UNKNOWN_INPUT +} CalcConsumeResult; + +typedef enum { + CALC_GET_RESULT_OK, + CALC_IS_EMPTY_BEFORE_READ, + CALC_NOT_EMPTY_AFTER_READ +} CalcGetResultResult; + +bool calcCreate(PostfixCalc **calc); + +CalcConsumeResult calcConsumeInput(PostfixCalc *calc, char input); + +CalcGetResultResult calcTryGetResult(PostfixCalc *calc, int *result); + +void calcDispose(PostfixCalc *calc); diff --git a/homework_5/task_2/test.c b/homework_5/task_2/test.c new file mode 100644 index 0000000..b1baa67 --- /dev/null +++ b/homework_5/task_2/test.c @@ -0,0 +1,102 @@ +#define CTEST_MAIN +#define CTEST_SEGFAULT +#include "../../ctest/ctest.h" + +#include "postfixCalc.h" + +int main(int argc, const char *argv[]) { + return ctest_main(argc, argv); +} + +PostfixCalc *createCalc(void) { + PostfixCalc *calc; + ASSERT_TRUE(calcCreate(&calc)); + ASSERT_NOT_NULL(calc); + + return calc; +} + +void assertResult(PostfixCalc *calc, int expected) { + int result = 0; + ASSERT_EQUAL(calcTryGetResult(calc, &result), CALC_GET_RESULT_OK); + ASSERT_EQUAL(expected, result); +} + +void assertConsumeString(PostfixCalc *calc, const char *input, int expected) { + for (int i = 0; input[i] != '\0'; ++i) { + ASSERT_EQUAL(calcConsumeInput(calc, input[i]), CALC_CONSUME_OK); + } + + assertResult(calc, expected); +} + +void testCalc(const char *input, int expected) { + PostfixCalc *calc = createCalc(); + + assertConsumeString(calc, input, expected); + + free(calc); +} + +CTEST(postfixCalcTests, createTest) { + PostfixCalc *calc = createCalc(); + free(calc); +} + +CTEST(postfixCalcTests, singleNumberTest) { + testCalc("4", 4); +} + +CTEST(postfixCalcTests, additionTest) { + testCalc("12+", 3); + testCalc("00+", 0); + testCalc("50+", 5); + testCalc("09+", 9); + testCalc("78+", 15); + testCalc("99+", 18); +} + +CTEST(postfixCalcTests, subtractionTest) { + testCalc("53-", 2); + testCalc("00-", 0); + testCalc("50-", 5); + testCalc("09-", -9); + testCalc("78-", -1); + testCalc("99-", 0); + testCalc("98-", 1); + testCalc("38-", -5); +} + +CTEST(postfixCalcTests, multiplicationTest) { + testCalc("53*", 15); + testCalc("00*", 0); + testCalc("50*", 0); + testCalc("09*", 0); + testCalc("78*", 56); + testCalc("99*", 81); + testCalc("98*", 72); + testCalc("38*", 24); + testCalc("88*", 64); +} + +CTEST(postfixCalcTests, divisionTest) { + testCalc("51/", 5); + testCalc("09/", 0); + testCalc("78/", 0); + testCalc("99/", 1); + testCalc("93/", 3); + testCalc("31/", 3); + testCalc("88/", 1); + testCalc("82/", 4); + testCalc("62/", 3); + testCalc("63/", 2); +} + +CTEST(postfixCalcTests, complexTest) { + testCalc("12+34++", 10); + testCalc("12+34+*", 21); + testCalc("12+34+*2*", 42); + testCalc("12*34*56***", 720); + + testCalc("96-12+*", 9); +} From aa811aeb4d0658298a21c22cf5cd27b456509550 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:29:11 +0300 Subject: [PATCH 2/7] Added comments (hw5 task 2) --- homework_5/task_2/postfixCalc.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/homework_5/task_2/postfixCalc.h b/homework_5/task_2/postfixCalc.h index 6e59905..12487d1 100644 --- a/homework_5/task_2/postfixCalc.h +++ b/homework_5/task_2/postfixCalc.h @@ -2,6 +2,12 @@ #include "stdbool.h" +/// @brief Calculator that works with basic operations like +/// addition, subtraction, multiplication and division +/// using integer numbers. +/// +/// Recieves expression character by character in +/// postfix notation(also known as Reverse Polish notation(PRN)) typedef struct PostfixCalc PostfixCalc; typedef enum { @@ -17,10 +23,33 @@ typedef enum { CALC_NOT_EMPTY_AFTER_READ } CalcGetResultResult; +/// @brief Creates `PostfixCalc` +/// @param stack Pointer to store created `PostfixCalc` to +/// @return `true` if successful, `false` otherwise (allocation failed) bool calcCreate(PostfixCalc **calc); +/// @brief Tries to read input to calculator +/// @param calc Pointer to `PostfixCalc` instance +/// @param input Input to read +/// @return `CALC_CONSUME_OK` if read successfully +/// +/// `CALC_CONSUME_NOT_ENOUGH_OPERANDS` if there were not enough operands provided before specified operator +/// +/// `CALC_CONSUME_UNKNOWN_INPUT` if unknown character was provided +/// +/// `CALC_CONSUME_ALLOCATION_ERROR` if allocation error ocurred internally CalcConsumeResult calcConsumeInput(PostfixCalc *calc, char input); +/// @brief Tries to get last result +/// @param calc Pointer to `PostfixCalc` instance +/// @param result Pointer to write evaluation result to +/// @return `CALC_GET_RESULT_OK` if evaluated successfully +/// +/// `CALC_IS_EMPTY_BEFORE_READ` if there wasn't any result to return +/// +/// `CALC_NOT_EMPTY_AFTER_READ` if there are more than one result CalcGetResultResult calcTryGetResult(PostfixCalc *calc, int *result); +/// @brief Disposes calculator +/// @param stack `PostfixCalc` to dispose void calcDispose(PostfixCalc *calc); From ef9dd2ed01faaba83e873e0fbbf01764ec34d28a Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:44:47 +0300 Subject: [PATCH 3/7] Fixed arguments in docs comments (hw5 task 2) --- homework_5/task_2/postfixCalc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homework_5/task_2/postfixCalc.h b/homework_5/task_2/postfixCalc.h index 12487d1..7ea5cef 100644 --- a/homework_5/task_2/postfixCalc.h +++ b/homework_5/task_2/postfixCalc.h @@ -24,7 +24,7 @@ typedef enum { } CalcGetResultResult; /// @brief Creates `PostfixCalc` -/// @param stack Pointer to store created `PostfixCalc` to +/// @param calc Pointer to store created `PostfixCalc` to /// @return `true` if successful, `false` otherwise (allocation failed) bool calcCreate(PostfixCalc **calc); @@ -51,5 +51,5 @@ CalcConsumeResult calcConsumeInput(PostfixCalc *calc, char input); CalcGetResultResult calcTryGetResult(PostfixCalc *calc, int *result); /// @brief Disposes calculator -/// @param stack `PostfixCalc` to dispose +/// @param calc `PostfixCalc` to dispose void calcDispose(PostfixCalc *calc); From 655e32f355d4add5a70ee10238d65be3ddf394a4 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 22 Oct 2024 23:05:10 +0300 Subject: [PATCH 4/7] Dispose calc properly --- homework_5/task_2/test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homework_5/task_2/test.c b/homework_5/task_2/test.c index b1baa67..753b85e 100644 --- a/homework_5/task_2/test.c +++ b/homework_5/task_2/test.c @@ -35,12 +35,12 @@ void testCalc(const char *input, int expected) { assertConsumeString(calc, input, expected); - free(calc); + calcDispose(calc); } CTEST(postfixCalcTests, createTest) { PostfixCalc *calc = createCalc(); - free(calc); + calcDispose(calc); } CTEST(postfixCalcTests, singleNumberTest) { From 1a722a597552d4d8e891f6441607e2ed760e1d3e Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 10 Dec 2024 03:17:23 +0300 Subject: [PATCH 5/7] Added stdbool.h includes and fixed already existing one (hw5 task 2) --- homework_5/task_2/main.c | 1 + homework_5/task_2/postfixCalc.c | 1 + homework_5/task_2/postfixCalc.h | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/homework_5/task_2/main.c b/homework_5/task_2/main.c index 4e24b41..ffa3722 100644 --- a/homework_5/task_2/main.c +++ b/homework_5/task_2/main.c @@ -1,3 +1,4 @@ +#include #include #include "postfixCalc.h" diff --git a/homework_5/task_2/postfixCalc.c b/homework_5/task_2/postfixCalc.c index bed6f8e..8fc2373 100644 --- a/homework_5/task_2/postfixCalc.c +++ b/homework_5/task_2/postfixCalc.c @@ -1,5 +1,6 @@ #include "postfixCalc.h" +#include #include #include "../stack/stack.h" diff --git a/homework_5/task_2/postfixCalc.h b/homework_5/task_2/postfixCalc.h index 7ea5cef..f0ffe86 100644 --- a/homework_5/task_2/postfixCalc.h +++ b/homework_5/task_2/postfixCalc.h @@ -1,6 +1,6 @@ #pragma once -#include "stdbool.h" +#include /// @brief Calculator that works with basic operations like /// addition, subtraction, multiplication and division From 5f53917252be602c5ccfa293c33da12638825086 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Sun, 22 Dec 2024 14:53:15 +0300 Subject: [PATCH 6/7] Fixed allocation check (hw5 task 2) --- homework_5/task_2/postfixCalc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homework_5/task_2/postfixCalc.c b/homework_5/task_2/postfixCalc.c index 8fc2373..8f5fd84 100644 --- a/homework_5/task_2/postfixCalc.c +++ b/homework_5/task_2/postfixCalc.c @@ -11,7 +11,7 @@ typedef struct PostfixCalc { bool calcCreate(PostfixCalc **calc) { *calc = malloc(sizeof(PostfixCalc)); - if (calc == NULL) { + if (*calc == NULL) { return false; } From 461d7c26ccbccd0b88205ffcf29a695529382460 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Sun, 22 Dec 2024 22:23:40 +0300 Subject: [PATCH 7/7] Added task name to README (hw5 task 2) --- homework_5/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/homework_5/README.md b/homework_5/README.md index c6918c2..574cc6e 100644 --- a/homework_5/README.md +++ b/homework_5/README.md @@ -1 +1,3 @@ # Homework 5 + +[Task 2. Postfix calculator](/homework_5/task_2)