From 201bdd2bee82849c6c5bc9dc113406c55af3d4dc Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Sun, 10 Nov 2024 04:40:14 +0300 Subject: [PATCH 1/5] Added homework 7 --- CMakeLists.txt | 2 ++ homework_7/CMakeLists.txt | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 homework_7/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e2e18b..fbae1cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,3 +3,5 @@ project(homework LANGUAGES C) set(CMAKE_C_STANDARD 23) set(CMAKE_C_STANDARD_REQUIRED TRUE) + +add_subdirectory(homework_7) diff --git a/homework_7/CMakeLists.txt b/homework_7/CMakeLists.txt new file mode 100644 index 0000000..d33f737 --- /dev/null +++ b/homework_7/CMakeLists.txt @@ -0,0 +1,3 @@ +project(homework_7) + +set(homeworkName "${PROJECT_NAME}") From 37a10a9525d9b6120e5d5c6e9585f92f4ddf21c1 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Mon, 11 Nov 2024 19:42:02 +0300 Subject: [PATCH 2/5] Homework 7 - task 1 --- homework_7/CMakeLists.txt | 2 + homework_7/task_1/.gitignore | 2 + homework_7/task_1/CMakeLists.txt | 9 ++ homework_7/task_1/expressionTree.c | 224 +++++++++++++++++++++++++++++ homework_7/task_1/expressionTree.h | 42 ++++++ homework_7/task_1/main.c | 43 ++++++ homework_7/task_1/test.c | 57 ++++++++ 7 files changed, 379 insertions(+) create mode 100644 homework_7/task_1/.gitignore create mode 100644 homework_7/task_1/CMakeLists.txt create mode 100644 homework_7/task_1/expressionTree.c create mode 100644 homework_7/task_1/expressionTree.h create mode 100644 homework_7/task_1/main.c create mode 100644 homework_7/task_1/test.c diff --git a/homework_7/CMakeLists.txt b/homework_7/CMakeLists.txt index d33f737..6c91639 100644 --- a/homework_7/CMakeLists.txt +++ b/homework_7/CMakeLists.txt @@ -1,3 +1,5 @@ project(homework_7) set(homeworkName "${PROJECT_NAME}") + +add_subdirectory(task_1) diff --git a/homework_7/task_1/.gitignore b/homework_7/task_1/.gitignore new file mode 100644 index 0000000..13d4d85 --- /dev/null +++ b/homework_7/task_1/.gitignore @@ -0,0 +1,2 @@ +inputTree.txt +testTree.txt diff --git a/homework_7/task_1/CMakeLists.txt b/homework_7/task_1/CMakeLists.txt new file mode 100644 index 0000000..6a13ad9 --- /dev/null +++ b/homework_7/task_1/CMakeLists.txt @@ -0,0 +1,9 @@ +project("${homeworkName}_task_1") + +add_library(expressionTree expressionTree.c) + +add_executable(${PROJECT_NAME} main.c) +target_link_libraries(${PROJECT_NAME} expressionTree) + +add_executable(${PROJECT_NAME}_test test.c) +target_link_libraries(${PROJECT_NAME}_test expressionTree) diff --git a/homework_7/task_1/expressionTree.c b/homework_7/task_1/expressionTree.c new file mode 100644 index 0000000..9bec13e --- /dev/null +++ b/homework_7/task_1/expressionTree.c @@ -0,0 +1,224 @@ +#include "expressionTree.h" + +#include +#include +#include + +typedef struct ExpressionNode { + int value; + struct ExpressionNode *left; + struct ExpressionNode *right; +} ExpressionNode; + +typedef struct ExpressionTree { + ExpressionNode *root; +} ExpressionTree; + +// return `true` if read, `false` if stream ended +static bool readChar(FILE *stream, char *value) { + int readResult = fgetc(stream); + if (readResult == EOF) { + return false; + } + *value = (char)readResult; + return true; +} + +static void trimWhiteSpace(FILE *stream) { + while (true) { + int value = fgetc(stream); + if (value == EOF) { + return; + } + if (value != ' ') { + ungetc(value, stream); + return; + } + } +} + +static bool readNode(FILE *stream, ExpressionNode **node); + +static bool readArgument(FILE *stream, ExpressionNode **argument) { + trimWhiteSpace(stream); + + char currentChar = '\0'; + if (!readChar(stream, ¤tChar)) { + return false; + } + + ungetc(currentChar, stream); + + if (currentChar == '(') { + return readNode(stream, argument); + } + + int value = 0; + if (fscanf(stream, "%d", &value) != 1) { + return false; + } + + ExpressionNode *node = malloc(sizeof(ExpressionNode)); + if (node == NULL) { + return false; + } + + node->value = value; + node->left = NULL; + node->right = NULL; + + *argument = node; + + return true; +} + +static bool readNode(FILE *stream, ExpressionNode **node) { + ExpressionNode *newNode = malloc(sizeof(ExpressionNode)); + if (newNode == NULL) { + return false; + } + + trimWhiteSpace(stream); + + char currentChar = '\0'; + if (!readChar(stream, ¤tChar)) { + return false; + } + + if (currentChar != '(') { + return false; + } + + trimWhiteSpace(stream); + + if (!readChar(stream, ¤tChar)) { + return false; + } + + if (!(currentChar == '+' || currentChar == '-' || currentChar == '*' || currentChar == '/')) { + return false; + } + + newNode->value = currentChar; + + if (!readArgument(stream, &newNode->left) || !readArgument(stream, &newNode->right)) { + return false; + } + + if (!readChar(stream, ¤tChar)) { + return false; + } + + if (currentChar != ')') { + return false; + } + + *node = newNode; + + return true; +} + +bool readExpressionTree(ExpressionTree **tree, FILE *stream) { + ExpressionTree *newTree = malloc(sizeof(ExpressionTree)); + if (newTree == NULL) { + return false; + } + + if (!readNode(stream, &newTree->root)) { + free(newTree); + return false; + } + + *tree = newTree; + + return true; +} + +static void printNodeAsTree(ExpressionNode *node, FILE *stream, int depth) { + if (depth != 0) { + fprintf(stream, " |"); + } + + for (int i = 1; i < depth; ++i) { + fprintf(stream, " |"); + } + + if (depth != 0) { + fprintf(stream, "-"); + } + + bool isValue = node->left == NULL || node->left == NULL; + + if (isValue) { + fprintf(stream, "[%d]\n", node->value); + } else { + fprintf(stream, "(%c)\n", node->value); + printNodeAsTree(node->left, stream, depth + 1); + printNodeAsTree(node->right, stream, depth + 1); + } +} + +static void printNodeAsExpression(ExpressionNode *node, FILE *stream, bool firstNode) { + bool isValue = node->left == NULL || node->left == NULL; + + if (isValue) { + fprintf(stream, "%d", node->value); + } else { + fprintf(stream, "("); + printNodeAsExpression(node->left, stream, false); + fprintf(stream, " %c ", node->value); + printNodeAsExpression(node->right, stream, false); + fprintf(stream, ")"); + } + if (firstNode) { + fprintf(stream, "\n"); + } +} + +void printAsTree(ExpressionTree *tree, FILE *stream) { + printNodeAsTree(tree->root, stream, 0); +} + +void printAsExpression(ExpressionTree *tree, FILE *stream) { + printNodeAsExpression(tree->root, stream, true); +} + +int evaluateNode(ExpressionNode *node) { + if (node->left == NULL || node->right == NULL) { + return node->value; + } + + int left = evaluateNode(node->left); + int right = evaluateNode(node->right); + switch (node->value) { + case '+': + return left + right; + case '-': + return left - right; + case '*': + return left * right; + case '/': + return left / right; + } + + return 0; +} + +int evaluateExpressionTree(ExpressionTree *tree) { + return evaluateNode(tree->root); +} + +void disposeNode(ExpressionNode *node) { + if (node == NULL) { + return; + } + disposeNode(node->left); + disposeNode(node->right); + + free(node); +} + +void disposeTree(ExpressionTree *tree) { + disposeNode(tree->root); + free(tree); +} diff --git a/homework_7/task_1/expressionTree.h b/homework_7/task_1/expressionTree.h new file mode 100644 index 0000000..0471964 --- /dev/null +++ b/homework_7/task_1/expressionTree.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +/// @brief Tree that represents arithmetic expression +typedef struct ExpressionTree ExpressionTree; + +/// @brief Reads expression tree from stream in format (`operator` `argumentA` `argumentB`), +/// where `operator` is eiter `+`, `-`, `*` or `/` and both `argumentA` and `argumentB` are +/// expressions or integer numbers +/// @param tree `ExpressionTree` pointer to write result into +/// @param stream Stream to read expression tree from +/// @return `true` if read successfully, `false` otherwise (allocation failed or incorrect format) +bool readExpressionTree(ExpressionTree **tree, FILE *stream); + +/// @brief Prints tree in tree form: +/// +/// `(operator)` +/// +/// ` |-[argumentA]` +/// +/// ` |-[argumentB]` +/// @param tree Tree to print +/// @param stream Stream to print tree to +void printAsTree(ExpressionTree *tree, FILE *stream); + +/// @brief Prints tree in expression form: +/// +/// `(argumentA operator argumentB)` +/// @param tree Tree to print +/// @param stream Stream to print tree to +void printAsExpression(ExpressionTree *tree, FILE *stream); + +/// @brief Evaluates expression represented by tree +/// @param tree Tree to evaluate +/// @return Evaluated value +int evaluateExpressionTree(ExpressionTree *tree); + +/// @brief Disposes tree +/// @param tree Tree to dispose +void disposeTree(ExpressionTree *tree); diff --git a/homework_7/task_1/main.c b/homework_7/task_1/main.c new file mode 100644 index 0000000..bea4be2 --- /dev/null +++ b/homework_7/task_1/main.c @@ -0,0 +1,43 @@ +#include +#include + +#include "expressionTree.h" + +bool readAndEvaluate(FILE *stream) { + ExpressionTree *tree = NULL; + + if (!readExpressionTree(&tree, stream)) { + return false; + } + + printf("tree form:\n"); + printAsTree(tree, stdout); + + printf("expression form:\n"); + printAsExpression(tree, stdout); + + printf("evaluates to %d\n", evaluateExpressionTree(tree)); + printf("\n"); + return true; +} + +int main(void) { + FILE *file = fopen("inputTree.txt", "r"); + if (file == NULL) { + printf("failed to open file\n"); + return 1; + } + + while (!feof(file)) { + if (!readAndEvaluate(file)) { + printf("failed to evaluate read and evaluate tree\n"); + } + + char value = fgetc(file); + while (value == '\n') { + value = fgetc(file); + } + ungetc(value, file); + } + fclose(file); +} diff --git a/homework_7/task_1/test.c b/homework_7/task_1/test.c new file mode 100644 index 0000000..91e37ed --- /dev/null +++ b/homework_7/task_1/test.c @@ -0,0 +1,57 @@ +#define CTEST_MAIN +#define CTEST_SEGFAULT +#include "../../ctest/ctest.h" + +#include + +#include "expressionTree.h" + +int main(int argc, const char *argv[]) { + return ctest_main(argc, argv); +} + +ExpressionTree *readTree(FILE *file) { + ExpressionTree *tree = NULL; + ASSERT_TRUE(readExpressionTree(&tree, file)); + ASSERT_NOT_NULL(tree); + + return tree; +} + +void assertExpression(const char *expression, int expectedResult) { + const char *filename = "testTree.txt"; + + FILE *file = fopen(filename, "w+"); + ASSERT_NOT_NULL(file); + fprintf(file, "%s\n", expression); + ASSERT_EQUAL(fclose(file), 0); + + file = fopen(filename, "r"); + ASSERT_NOT_NULL(file); + ExpressionTree *tree = readTree(file); + ASSERT_EQUAL(fclose(file), 0); + + ASSERT_EQUAL(evaluateExpressionTree(tree), expectedResult); + + disposeTree(tree); +} + +CTEST(expressionTreeTests, singleExpressionTest) { + assertExpression("(+ 2 3)", (2 + 3)); + assertExpression("(- 24 14)", (24 - 14)); + assertExpression("(* 15 17)", (15 * 17)); + assertExpression("(/ 45 10)", (45 / 10)); +} + +CTEST(expressionTreeTests, twoNestedExpressionTest) { + assertExpression("(* (+ 12 11) 21)", ((12 + 11) * 21)); + assertExpression("(- 64 (* 7 9))", (64 - (7 * 9))); + assertExpression("(+ (* 2 1) (/ 6 2))", ((2 * 1) + (6 / 2))); + assertExpression("(* (* 4 9) (- 5 -4))", ((4 * 9) * (5 - (-4)))); + assertExpression("(+ (- 23 4) (* 3 21))", ((23 - 4) + (3 * 21))); +} + +CTEST(expressionTreeTests, nestedExpressionTest) { + assertExpression("(/ (* 2 (+ -1 (/ -12 12))) (* 2 4))", ((2 * (-1 + (-12 / 12))) / (2 * 4))); + assertExpression("(* 2 (+ 1 (/ 12 12)))", (2 * (1 + (12 / 12)))); +} From 2ebca9c4d2a68964084db5678bf1b5b7d1fed473 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Fri, 29 Nov 2024 20:24:05 +0300 Subject: [PATCH 3/5] Remove temporary file after test (hw7 task 1) --- homework_7/task_1/test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/homework_7/task_1/test.c b/homework_7/task_1/test.c index 91e37ed..6b5b2c7 100644 --- a/homework_7/task_1/test.c +++ b/homework_7/task_1/test.c @@ -30,6 +30,7 @@ void assertExpression(const char *expression, int expectedResult) { ASSERT_NOT_NULL(file); ExpressionTree *tree = readTree(file); ASSERT_EQUAL(fclose(file), 0); + ASSERT_EQUAL(remove(filename), 0); ASSERT_EQUAL(evaluateExpressionTree(tree), expectedResult); From 583642bb32d3382b7e5c8e36d8bdef6bd6191fd2 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Wed, 25 Dec 2024 19:33:02 +0300 Subject: [PATCH 4/5] Added README (hw7) --- homework_7/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 homework_7/README.md diff --git a/homework_7/README.md b/homework_7/README.md new file mode 100644 index 0000000..20152e5 --- /dev/null +++ b/homework_7/README.md @@ -0,0 +1 @@ +# Homework 7 From a453735e69b58f56f83b1eec6859fed3cd747cde Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Wed, 25 Dec 2024 19:33:57 +0300 Subject: [PATCH 5/5] Added task name to README (hw7 task 1) --- homework_7/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/homework_7/README.md b/homework_7/README.md index 20152e5..3507fa2 100644 --- a/homework_7/README.md +++ b/homework_7/README.md @@ -1 +1,3 @@ # Homework 7 + +[Task 1. Expression tree](/homework_7/task_1)