Skip to content
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ add_subdirectory(homework_2)
add_subdirectory(homework_3)
add_subdirectory(homework_4)
add_subdirectory(homework_5)
add_subdirectory(homework_7)
add_subdirectory(homework_8)
add_subdirectory(homework_9)
5 changes: 5 additions & 0 deletions homework_7/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
project(homework_7)

set(homeworkName "${PROJECT_NAME}")

add_subdirectory(task_1)
3 changes: 3 additions & 0 deletions homework_7/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Homework 7

[Task 1. Expression tree](/homework_7/task_1)
2 changes: 2 additions & 0 deletions homework_7/task_1/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
inputTree.txt
testTree.txt
9 changes: 9 additions & 0 deletions homework_7/task_1/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
224 changes: 224 additions & 0 deletions homework_7/task_1/expressionTree.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
#include "expressionTree.h"

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

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, &currentChar)) {
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, &currentChar)) {
return false;
}

if (currentChar != '(') {
return false;
}

trimWhiteSpace(stream);

if (!readChar(stream, &currentChar)) {
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, &currentChar)) {
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);
}
42 changes: 42 additions & 0 deletions homework_7/task_1/expressionTree.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#pragma once

#include <stdbool.h>
#include <stdio.h>

/// @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);
43 changes: 43 additions & 0 deletions homework_7/task_1/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include <stdbool.h>
#include <stdio.h>

#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);
}
Loading