mirror of
				https://github.com/sloven-c/calculator.git
				synced 2025-11-04 14:17:23 +01:00 
			
		
		
		
	Initial commit
This commit is contained in:
		
							
								
								
									
										11
									
								
								CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					cmake_minimum_required(VERSION 4.0)
 | 
				
			||||||
 | 
					project(calculator C)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set(CMAKE_C_STANDARD 23)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					add_executable(calculator main.c
 | 
				
			||||||
 | 
					        structures.h
 | 
				
			||||||
 | 
					        stack.c
 | 
				
			||||||
 | 
					        stack.h
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					target_link_libraries(calculator m)
 | 
				
			||||||
							
								
								
									
										295
									
								
								main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								main.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,295 @@
 | 
				
			|||||||
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					#include <math.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "stack.h"
 | 
				
			||||||
 | 
					#include "structures.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int calculate_stack(const stack *output_queue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int str_to_num(char *string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int calculate(int a, int b, char op);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					string get_expression(int argc, char *argv[]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stack get_output_queue(const stack *tokenisedExpression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int push_operator(char operatorToPush, stack *output_stack, stack *operator_stack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool stack_higher_precedence(char op, char stackOp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stack split_into_tokens(string expression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					string get_slice(int a, size_t b, const char *expression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool validate_expression(const char *expression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					charResult validate_char(char c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void validate_malloc(const void *p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void throw_error(char *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *OPERATORS[] = {"+-", "*/", "^", "()"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(const int argc, char *argv[]) {
 | 
				
			||||||
 | 
					    const string expression = get_expression(argc, argv);
 | 
				
			||||||
 | 
					    if (expression.string == nullptr) return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    stack tokens = split_into_tokens(expression);
 | 
				
			||||||
 | 
					    stack_print(&tokens, "Tokens");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    stack output_queue = get_output_queue(&tokens);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    printf("%d\n", calculate_stack(&output_queue));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    stack_deinit(&output_queue);
 | 
				
			||||||
 | 
					    stack_deinit(&tokens);
 | 
				
			||||||
 | 
					    free(expression.string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int calculate_stack(const stack *output_queue) {
 | 
				
			||||||
 | 
					    stack calculation_stack = stack_init(IntArray, output_queue->len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (size_t i = 0; i <= output_queue->i; i++) {
 | 
				
			||||||
 | 
					        const stackData element = stack_get(output_queue, i);
 | 
				
			||||||
 | 
					        if (element.ret_code == 1)
 | 
				
			||||||
 | 
					            throw_error("Couldn't retrieve element from output queue for calculation stack push");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch (validate_char(element.data.string[0]).type) {
 | 
				
			||||||
 | 
					            case Digit:
 | 
				
			||||||
 | 
					                const int n = str_to_num(element.data.string);
 | 
				
			||||||
 | 
					                const int r = stack_push(&calculation_stack, (stackInput){.n = n}, false);
 | 
				
			||||||
 | 
					                if (r == 1) throw_error("Failed to push number to calculation stack");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Operator:
 | 
				
			||||||
 | 
					                const stackData aP = stack_pop(&calculation_stack);
 | 
				
			||||||
 | 
					                const stackData bP = stack_pop(&calculation_stack);
 | 
				
			||||||
 | 
					                if (aP.ret_code == 1 || bP.ret_code == 1) throw_error("Failed to pop numbers from calculation stack");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                const int result = calculate(aP.data.n, bP.data.n, element.data.string[0]);
 | 
				
			||||||
 | 
					                const int rSp = stack_push(&calculation_stack, (stackInput){.n = result}, false);
 | 
				
			||||||
 | 
					                if (rSp == 1) throw_error("Error while trying to push result into calculation stack");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Invalid:
 | 
				
			||||||
 | 
					                fprintf(stderr, "The following string is not valid part of expression: '%s'\n", element.data.string);
 | 
				
			||||||
 | 
					                throw_error(nullptr);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const stackData res = stack_get(&calculation_stack, 0);
 | 
				
			||||||
 | 
					    if (res.ret_code == 1) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "Calculation stack index should be at position 0 but is at %d!\n", calculation_stack.i);
 | 
				
			||||||
 | 
					        throw_error(nullptr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return res.data.n;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int str_to_num(char *string) {
 | 
				
			||||||
 | 
					    char *endptr;
 | 
				
			||||||
 | 
					    const int num = (int) strtol(string, &endptr, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (endptr == string || *endptr != 0x0) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "Failed to convert the '%s' string to number\n", string);
 | 
				
			||||||
 | 
					        throw_error(nullptr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return num;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReSharper disable once CppNotAllPathsReturnValue
 | 
				
			||||||
 | 
					int calculate(const int a, const int b, const char op) {
 | 
				
			||||||
 | 
					    switch (op) {
 | 
				
			||||||
 | 
					        case '+':
 | 
				
			||||||
 | 
					            return a + b;
 | 
				
			||||||
 | 
					        case '-':
 | 
				
			||||||
 | 
					            return a - b;
 | 
				
			||||||
 | 
					        case '*':
 | 
				
			||||||
 | 
					            return a * b;
 | 
				
			||||||
 | 
					        case '/':
 | 
				
			||||||
 | 
					            return a / b;
 | 
				
			||||||
 | 
					        case '^':
 | 
				
			||||||
 | 
					            return (int) pow(a, b);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fprintf(stderr, "Operator '%c' is invalid\n", op);
 | 
				
			||||||
 | 
					    throw_error(nullptr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					string get_expression(const int argc, char *argv[]) {
 | 
				
			||||||
 | 
					    string ex = {.string = nullptr};
 | 
				
			||||||
 | 
					    if (argc <= 1) return ex; // first argument is just program name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t len = 0;
 | 
				
			||||||
 | 
					    for (size_t i = 1; i < argc; i++) {
 | 
				
			||||||
 | 
					        len += strlen(argv[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const size_t totalLen = len * sizeof(char) + 1; // +1 => \0 (0x0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *expression = malloc(totalLen);
 | 
				
			||||||
 | 
					    validate_malloc(expression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expression[0] = '\0'; // since the following will cat string, we need to set the end or rather start point
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (size_t i = 1; i < argc; i++) {
 | 
				
			||||||
 | 
					        strlcat(expression, argv[i], totalLen);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (validate_expression(expression)) {
 | 
				
			||||||
 | 
					        ex.string = expression;
 | 
				
			||||||
 | 
					        ex.len = totalLen;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        free(expression);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ex;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// we could not return anything and just send pointer to stack?
 | 
				
			||||||
 | 
					stack get_output_queue(const stack *tokenisedExpression) {
 | 
				
			||||||
 | 
					    stack output_stack = stack_init(StringArray, tokenisedExpression->len);
 | 
				
			||||||
 | 
					    stack operator_stack = stack_init(CharArray, tokenisedExpression->len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < tokenisedExpression->i; i++) {
 | 
				
			||||||
 | 
					        const stackData token = stack_get(tokenisedExpression, i);
 | 
				
			||||||
 | 
					        if (token.ret_code == 1) throw_error("Failed to retrieve token");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (validate_char(token.data.string[0]).type == Operator) {
 | 
				
			||||||
 | 
					            // do operator shit
 | 
				
			||||||
 | 
					            const int ret = push_operator(token.data.string[0], &output_stack, &operator_stack);
 | 
				
			||||||
 | 
					            if (ret == 1) throw_error("Failed to push operator");
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // push number to output queue
 | 
				
			||||||
 | 
					            stack_push(&output_stack, token.data, false);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // pop everything from operator to output stack
 | 
				
			||||||
 | 
					    while (operator_stack.i >= 0) {
 | 
				
			||||||
 | 
					        const stackData popOp = stack_pop(&operator_stack);
 | 
				
			||||||
 | 
					        if (popOp.ret_code == 1) throw_error("Failed to retrieve operator from stack");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const int ret = stack_push(&output_stack, popOp.data, true);
 | 
				
			||||||
 | 
					        if (ret == 1) throw_error("Failed to push operator to output");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    stack_deinit(&operator_stack);
 | 
				
			||||||
 | 
					    return output_stack;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// push operator to operator queue and
 | 
				
			||||||
 | 
					int push_operator(const char operatorToPush, stack *output_stack, stack *operator_stack) {
 | 
				
			||||||
 | 
					    if (operatorToPush == '(') {
 | 
				
			||||||
 | 
					        return stack_push(operator_stack, (stackInput){.ch = operatorToPush}, false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (operatorToPush == ')') {
 | 
				
			||||||
 | 
					        for (stackData el = stack_pop(operator_stack); el.data.ch != '('; el = stack_pop(operator_stack)) {
 | 
				
			||||||
 | 
					            if (el.ret_code == 1) return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const int r = stack_push(output_stack, el.data, true);
 | 
				
			||||||
 | 
					            if (r == 1) return 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (stackData lastStackOp = stack_get(operator_stack, operator_stack->i);
 | 
				
			||||||
 | 
					         stack_higher_precedence(operatorToPush, lastStackOp.data.ch);
 | 
				
			||||||
 | 
					         lastStackOp = stack_get(operator_stack, operator_stack->i)) {
 | 
				
			||||||
 | 
					        if (lastStackOp.ret_code == 1) return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const stackData opToPush = stack_pop(operator_stack);
 | 
				
			||||||
 | 
					        if (opToPush.ret_code == 1) return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const int r = stack_push(output_stack, opToPush.data, true);
 | 
				
			||||||
 | 
					        if (r == 1) return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return stack_push(operator_stack, (stackInput){.ch = operatorToPush}, true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool stack_higher_precedence(const char op, const char stackOp) {
 | 
				
			||||||
 | 
					    return validate_char(stackOp).opPrecedence > validate_char(op).opPrecedence;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stack split_into_tokens(const string expression) {
 | 
				
			||||||
 | 
					    stack tokenisedExpression = stack_init(StringArray, expression.len);
 | 
				
			||||||
 | 
					    int lastOp = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < expression.len; i++) {
 | 
				
			||||||
 | 
					        if (validate_char(expression.string[i]).type != Operator) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const string slice = get_slice(lastOp, i, expression.string);
 | 
				
			||||||
 | 
					        if (slice.string != nullptr) {
 | 
				
			||||||
 | 
					            const int ret = stack_push(&tokenisedExpression, (stackInput){.string = slice.string}, false);
 | 
				
			||||||
 | 
					            if (ret == 1) throw_error("Failed to push slice into stack");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const int ret = stack_push(&tokenisedExpression, (stackInput){.ch = expression.string[i]}, true);
 | 
				
			||||||
 | 
					        if (ret == 1) throw_error("Failed to push current operator into stack");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        lastOp = i;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return tokenisedExpression;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// todo fix edge case on beginning
 | 
				
			||||||
 | 
					string get_slice(int a, size_t b, const char *expression) {
 | 
				
			||||||
 | 
					    const size_t len = b - abs(a) - 1;
 | 
				
			||||||
 | 
					    if (len < 1) return (string){.string = nullptr};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const size_t total_len = len * sizeof(char) + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *slice = malloc(total_len);
 | 
				
			||||||
 | 
					    validate_malloc(slice);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (const size_t i = ++a; a < b; a++) {
 | 
				
			||||||
 | 
					        // we don't track i separately but how much has a moved since we started creating the slice
 | 
				
			||||||
 | 
					        slice[a - i] = expression[a];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (string){slice, total_len};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool validate_expression(const char *expression) {
 | 
				
			||||||
 | 
					    for (const char *it = expression; *it != '\0'; it++) {
 | 
				
			||||||
 | 
					        if (validate_char(*it).type == Invalid) return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					charResult validate_char(const char c) {
 | 
				
			||||||
 | 
					    if (isdigit(c)) return (charResult){Digit, 0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i = 0; i < sizeof(OPERATORS); i++) {
 | 
				
			||||||
 | 
					        for (int j = 0; j < sizeof(OPERATORS[i]); j++) {
 | 
				
			||||||
 | 
					            if (c == OPERATORS[i][j])
 | 
				
			||||||
 | 
					                return (charResult){Operator, i};
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (charResult){Invalid, 0};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void validate_malloc(const void *p) {
 | 
				
			||||||
 | 
					    if (p != NULL) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    throw_error("Failed to allocate memory");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void throw_error(char *msg) {
 | 
				
			||||||
 | 
					    if (msg != nullptr)
 | 
				
			||||||
 | 
					        fprintf(stderr, "%s\n", msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										162
									
								
								stack.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								stack.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,162 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by marto on 27. 10. 25.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include "stack.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stack stack_init(const DataType type, const int len) {
 | 
				
			||||||
 | 
					    stack stack = {
 | 
				
			||||||
 | 
					        .type = type,
 | 
				
			||||||
 | 
					        .i = -1,
 | 
				
			||||||
 | 
					        .len = len,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const size_t arrLen = len * sizeof(char);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (type) {
 | 
				
			||||||
 | 
					        case StringArray:
 | 
				
			||||||
 | 
					            stack.data.sarr = malloc(arrLen);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case CharArray:
 | 
				
			||||||
 | 
					            stack.data.carr = malloc(arrLen);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case IntArray:
 | 
				
			||||||
 | 
					            stack.data.narr = malloc(arrLen);
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            fprintf(stderr, "Failed to recognise the DataType for Stack structure");
 | 
				
			||||||
 | 
					            exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ReSharper disable once CppSomeObjectMembersMightNotBeInitialized
 | 
				
			||||||
 | 
					    return stack;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void stack_deinit(stack *stack) {
 | 
				
			||||||
 | 
					    switch (stack->type) {
 | 
				
			||||||
 | 
					        case StringArray:
 | 
				
			||||||
 | 
					            clear_str_array(stack);
 | 
				
			||||||
 | 
					            free(stack->data.sarr);
 | 
				
			||||||
 | 
					            stack->data.sarr = nullptr;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case CharArray:
 | 
				
			||||||
 | 
					            free(stack->data.carr);
 | 
				
			||||||
 | 
					            stack->data.carr = nullptr;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case IntArray:
 | 
				
			||||||
 | 
					            free(stack->data.narr);
 | 
				
			||||||
 | 
					            stack->data.narr = nullptr;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int stack_push(stack *stack, const stackInput input, const bool pushCharToString) {
 | 
				
			||||||
 | 
					    if (stack->i >= stack->len - 1) return 1;
 | 
				
			||||||
 | 
					    stack->i++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (stack->type) {
 | 
				
			||||||
 | 
					        case StringArray:
 | 
				
			||||||
 | 
					            char *str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // if we still push to array of strings but we're pushing single character as string
 | 
				
			||||||
 | 
					            if (pushCharToString) {
 | 
				
			||||||
 | 
					                str = malloc(sizeof(char) + 1);
 | 
				
			||||||
 | 
					                str[0] = input.ch;
 | 
				
			||||||
 | 
					                str[1] = 0x0;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                str = malloc(strlen(input.string) * sizeof(char) + 1);
 | 
				
			||||||
 | 
					                strcpy(str, input.string);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            stack->data.sarr[stack->i] = str;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case CharArray:
 | 
				
			||||||
 | 
					            stack->data.carr[stack->i] = input.ch;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case IntArray:
 | 
				
			||||||
 | 
					            stack->data.narr[stack->i] = input.n;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stackData stack_pop(stack *stack) {
 | 
				
			||||||
 | 
					    if (stack->i == -1) return (stackData){.ret_code = 1};
 | 
				
			||||||
 | 
					    stackInput returnData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (stack->type) {
 | 
				
			||||||
 | 
					        case StringArray:
 | 
				
			||||||
 | 
					            returnData.string = stack->data.sarr[stack->i];
 | 
				
			||||||
 | 
					            // todo might have to do malloc?
 | 
				
			||||||
 | 
					            // todo ticking timebomb
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case CharArray:
 | 
				
			||||||
 | 
					            returnData.ch = stack->data.carr[stack->i];
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case IntArray:
 | 
				
			||||||
 | 
					            returnData.n = stack->data.narr[stack->i];
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    stack->i--;
 | 
				
			||||||
 | 
					    return (stackData){returnData, 0};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stackData stack_get(const stack *stack, const int n) {
 | 
				
			||||||
 | 
					    if (stack->i == -1 || n >= stack->len) return (stackData){.ret_code = 1};
 | 
				
			||||||
 | 
					    stackInput returnData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (stack->type) {
 | 
				
			||||||
 | 
					        case StringArray:
 | 
				
			||||||
 | 
					            returnData.string = stack->data.sarr[stack->i];
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case CharArray:
 | 
				
			||||||
 | 
					            returnData.ch = stack->data.carr[stack->i];
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case IntArray:
 | 
				
			||||||
 | 
					            returnData.n = stack->data.narr[stack->i];
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (stackData){returnData, 0};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void stack_print(const stack *stack, const char *name) {
 | 
				
			||||||
 | 
					    printf("Printing stack %s:\n", name);
 | 
				
			||||||
 | 
					    if (stack->i == -1) return (void) printf("NULL\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i = 0; i <= stack->i; i++) {
 | 
				
			||||||
 | 
					        const stackData el = stack_get(stack, i);
 | 
				
			||||||
 | 
					        if (el.ret_code == 1) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "Invalid index\n");
 | 
				
			||||||
 | 
					            exit(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        printf("[%d]: ", i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch (stack->type) {
 | 
				
			||||||
 | 
					            case StringArray:
 | 
				
			||||||
 | 
					                printf("'%s'", el.data.string);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case CharArray:
 | 
				
			||||||
 | 
					                printf("'%c'", el.data.ch);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case IntArray:
 | 
				
			||||||
 | 
					                printf("'%d'", el.data.n);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        printf("\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    printf("\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void clear_str_array(const stack *stack) {
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < stack->len; i++) {
 | 
				
			||||||
 | 
					        free(stack->data.sarr[i]);
 | 
				
			||||||
 | 
					        stack->data.sarr[i] = nullptr;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										52
									
								
								stack.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								stack.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by marto on 27. 10. 25.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CALCULATOR_STACK_H
 | 
				
			||||||
 | 
					#define CALCULATOR_STACK_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    StringArray,
 | 
				
			||||||
 | 
					    CharArray,
 | 
				
			||||||
 | 
					    IntArray,
 | 
				
			||||||
 | 
					} DataType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    DataType type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    union {
 | 
				
			||||||
 | 
					        char **sarr;
 | 
				
			||||||
 | 
					        char *carr;
 | 
				
			||||||
 | 
					        int *narr;
 | 
				
			||||||
 | 
					    } data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // if i >= len, the program's guardrails have failed
 | 
				
			||||||
 | 
					    int i, len;
 | 
				
			||||||
 | 
					} stack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef union {
 | 
				
			||||||
 | 
					    char ch;
 | 
				
			||||||
 | 
					    char *string;
 | 
				
			||||||
 | 
					    int n;
 | 
				
			||||||
 | 
					} stackInput;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    stackInput data;
 | 
				
			||||||
 | 
					    int ret_code;
 | 
				
			||||||
 | 
					} stackData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stack stack_init(DataType type, int len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void stack_deinit(stack *stack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int stack_push(stack *stack, stackInput input, bool pushCharToString);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stackData stack_pop(stack *stack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					stackData stack_get(const stack *stack, int n);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void stack_print(const stack *stack, const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void clear_str_array(const stack *stack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif //CALCULATOR_STACK_H
 | 
				
			||||||
							
								
								
									
										24
									
								
								structures.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								structures.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					//
 | 
				
			||||||
 | 
					// Created by marto on 25. 10. 25.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CALCULATOR_STRUCTURES_H
 | 
				
			||||||
 | 
					#define CALCULATOR_STRUCTURES_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    Digit,
 | 
				
			||||||
 | 
					    Operator,
 | 
				
			||||||
 | 
					    Invalid,
 | 
				
			||||||
 | 
					} charType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    charType type;
 | 
				
			||||||
 | 
					    size_t opPrecedence;
 | 
				
			||||||
 | 
					} charResult;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    char *string;
 | 
				
			||||||
 | 
					    int len;
 | 
				
			||||||
 | 
					} string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif //CALCULATOR_STRUCTURES_H
 | 
				
			||||||
		Reference in New Issue
	
	Block a user