mirror of
				https://github.com/sloven-c/calculator.git
				synced 2025-11-04 14:17:23 +01:00 
			
		
		
		
	Fixed more footguns
This commit is contained in:
		
							
								
								
									
										53
									
								
								main.c
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								main.c
									
									
									
									
									
								
							@@ -34,14 +34,23 @@ void validate_malloc(const void *p);
 | 
				
			|||||||
void throw_error(char *msg);
 | 
					void throw_error(char *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(const int argc, char *argv[]) {
 | 
					int main(const int argc, char *argv[]) {
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * TODO
 | 
				
			||||||
 | 
					     * Implement calculating with negative numbers
 | 
				
			||||||
 | 
					     * and if you're suicidal enough calculation with floats
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    const string expression = get_expression(argc, argv);
 | 
					    const string expression = get_expression(argc, argv);
 | 
				
			||||||
    if (expression.string == nullptr) return 0;
 | 
					    if (expression.string == nullptr) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "Couldn't parse the expression\n");
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stack tokens = split_into_tokens(expression);
 | 
					    stack tokens = split_into_tokens(expression);
 | 
				
			||||||
    stack_print(&tokens, "tokens");
 | 
					    // stack_print(&tokens, "tokens");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stack output_queue = get_output_queue(&tokens);
 | 
					    stack output_queue = get_output_queue(&tokens);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // stack_print(&output_queue, "Output");
 | 
				
			||||||
    printf("%d\n", calculate_stack(&output_queue));
 | 
					    printf("%d\n", calculate_stack(&output_queue));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stack_deinit(&output_queue);
 | 
					    stack_deinit(&output_queue);
 | 
				
			||||||
@@ -66,9 +75,11 @@ int calculate_stack(const stack *output_queue) {
 | 
				
			|||||||
                if (r == 1) throw_error("Failed to push number to calculation stack");
 | 
					                if (r == 1) throw_error("Failed to push number to calculation stack");
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case Operator:
 | 
					            case Operator:
 | 
				
			||||||
                const stackData aP = stack_pop(&calculation_stack);
 | 
					 | 
				
			||||||
                const stackData bP = 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 stackData aP = 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 result = calculate(aP.data.n, bP.data.n, element.data.string[0]);
 | 
				
			||||||
                const int rSp = stack_push(&calculation_stack, (stackInput){.n = result}, false);
 | 
					                const int rSp = stack_push(&calculation_stack, (stackInput){.n = result}, false);
 | 
				
			||||||
@@ -76,7 +87,8 @@ int calculate_stack(const stack *output_queue) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case Invalid:
 | 
					            case Invalid:
 | 
				
			||||||
                fprintf(stderr, "The following string is not valid part of expression: '%s'\n", element.data.string);
 | 
					                fprintf(stderr, "The following string is not valid part of expression: '%s'\n",
 | 
				
			||||||
 | 
					                        element.data.string);
 | 
				
			||||||
                throw_error(nullptr);
 | 
					                throw_error(nullptr);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -168,6 +180,9 @@ stack get_output_queue(const stack *tokenisedExpression) {
 | 
				
			|||||||
            // push number to output queue
 | 
					            // push number to output queue
 | 
				
			||||||
            stack_push(&output_stack, token.data, false);
 | 
					            stack_push(&output_stack, token.data, false);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // printf("pushing output stack, i = %lu\n", i);
 | 
				
			||||||
 | 
					        // stack_print(&output_stack, "Output");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // pop everything from operator to output stack
 | 
					    // pop everything from operator to output stack
 | 
				
			||||||
@@ -198,24 +213,22 @@ int push_operator(const char operatorToPush, stack *output_stack, stack *operato
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    stackData lastStackOp = stack_get(operator_stack, operator_stack->i);
 | 
				
			||||||
    for (stackData lastStackOp = stack_get(operator_stack, operator_stack->i);
 | 
					    while (lastStackOp.ret_code == 0 && stack_higher_precedence(operatorToPush, lastStackOp.data.ch)) {
 | 
				
			||||||
         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);
 | 
					        const stackData opToPush = stack_pop(operator_stack);
 | 
				
			||||||
        if (opToPush.ret_code == 1) return 1;
 | 
					        if (opToPush.ret_code == 1) return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const int r = stack_push(output_stack, opToPush.data, true);
 | 
					        const int r = stack_push(output_stack, opToPush.data, true);
 | 
				
			||||||
        if (r == 1) return 1;
 | 
					        if (r == 1) return 1;
 | 
				
			||||||
 | 
					        lastStackOp = stack_get(operator_stack, operator_stack->i);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return stack_push(operator_stack, (stackInput){.ch = operatorToPush}, true);
 | 
					    return stack_push(operator_stack, (stackInput){.ch = operatorToPush}, true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool stack_higher_precedence(const char op, const char stackOp) {
 | 
					bool stack_higher_precedence(const char op, const char stackOp) {
 | 
				
			||||||
    const int stackOpPrecedence = validate_char(stackOp).opPrecedence, opPrecedence = validate_char(op).opPrecedence;
 | 
					    const int stackOpPrecedence = validate_char(stackOp).opPrecedence, opPrecedence = validate_char(op).
 | 
				
			||||||
 | 
					            opPrecedence;
 | 
				
			||||||
    if (stackOpPrecedence == -1 || opPrecedence == -1) return false;
 | 
					    if (stackOpPrecedence == -1 || opPrecedence == -1) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return stackOpPrecedence > opPrecedence;
 | 
					    return stackOpPrecedence > opPrecedence;
 | 
				
			||||||
@@ -226,8 +239,11 @@ stack split_into_tokens(const string expression) {
 | 
				
			|||||||
    int lastOp = -1;
 | 
					    int lastOp = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // -1 is to not push \0 onto stack
 | 
					    // -1 is to not push \0 onto stack
 | 
				
			||||||
    for (size_t i = 0; i < expression.len - 1; i++) {
 | 
					    for (size_t i = 0; i < expression.len; i++) {
 | 
				
			||||||
        if (validate_char(expression.string[i]).type != Operator) continue;
 | 
					        // we track if we reached \0 so we can make sure the  last number gets pushed onto the stack
 | 
				
			||||||
 | 
					        // as we only do stack pushing when we reach an operator or in this case \0
 | 
				
			||||||
 | 
					        const bool reached_eof = expression.string[i] == 0x0 && lastOp != i - 1;
 | 
				
			||||||
 | 
					        if (validate_char(expression.string[i]).type != Operator && !reached_eof) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const string slice = get_slice(lastOp, i, expression.string);
 | 
					        const string slice = get_slice(lastOp, i, expression.string);
 | 
				
			||||||
        if (slice.string != nullptr) {
 | 
					        if (slice.string != nullptr) {
 | 
				
			||||||
@@ -236,6 +252,7 @@ stack split_into_tokens(const string expression) {
 | 
				
			|||||||
            if (ret == 1) throw_error("Failed to push slice into stack");
 | 
					            if (ret == 1) throw_error("Failed to push slice into stack");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (reached_eof) break; // do not push \0 into token stack
 | 
				
			||||||
        const int ret = stack_push(&tokenisedExpression, (stackInput){.ch = expression.string[i]}, true);
 | 
					        const int ret = stack_push(&tokenisedExpression, (stackInput){.ch = expression.string[i]}, true);
 | 
				
			||||||
        if (ret == 1) throw_error("Failed to push current operator into stack");
 | 
					        if (ret == 1) throw_error("Failed to push current operator into stack");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -272,13 +289,15 @@ bool validate_expression(const char *expression) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
charResult validate_char(const char c) {
 | 
					charResult validate_char(const char c) {
 | 
				
			||||||
    if (isdigit(c)) return (charResult){Digit, 0};
 | 
					    if (isdigit(c)) return (charResult){Digit, 0};
 | 
				
			||||||
 | 
					    // todo maybe we it'd be better to just have it as const instead of creating it every time we call this function
 | 
				
			||||||
    const char *OPERATORS[] = {"+-", "*/", "^", "()"};
 | 
					    const char *OPERATORS[] = {"+-", "*/", "^", "()"};
 | 
				
			||||||
 | 
					    constexpr int OP_LEN = sizeof(OPERATORS) / sizeof(OPERATORS[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (int i = 0; i < sizeof(OPERATORS); i++) {
 | 
					    for (int i = 0; i < OP_LEN; i++) {
 | 
				
			||||||
        for (int j = 0; j < sizeof(OPERATORS[i]); j++) {
 | 
					        for (int j = 0; j < strlen(OPERATORS[i]); j++) {
 | 
				
			||||||
            if (c == OPERATORS[i][j])
 | 
					            if (c == OPERATORS[i][j])
 | 
				
			||||||
                // if the operators are parenthesis return 'invalid' precedence
 | 
					                // if the operators are parenthesis return 'invalid' precedence
 | 
				
			||||||
                return (charResult){Operator, i == sizeof(OPERATORS) - 1 ? -1 : i};
 | 
					                return (charResult){Operator, i == OP_LEN - 1 ? -1 : i};
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								stack.c
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								stack.c
									
									
									
									
									
								
							@@ -26,6 +26,7 @@ stack stack_init(const DataType type, const int len) {
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case IntArray:
 | 
					        case IntArray:
 | 
				
			||||||
            stack.data.narr = malloc(arrLen * sizeof(int));
 | 
					            stack.data.narr = malloc(arrLen * sizeof(int));
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            fprintf(stderr, "Failed to recognise the DataType for Stack structure");
 | 
					            fprintf(stderr, "Failed to recognise the DataType for Stack structure");
 | 
				
			||||||
            exit(1);
 | 
					            exit(1);
 | 
				
			||||||
@@ -84,14 +85,16 @@ int stack_push(stack *stack, const stackInput input, const bool pushCharToString
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
stackData stack_pop(stack *stack) {
 | 
					stackData stack_pop(stack *stack) {
 | 
				
			||||||
 | 
					    // TODO in the future we have to think of solution to clear stackData after we're done with it
 | 
				
			||||||
 | 
					    // TODO maybe fn stack_pop_free()?
 | 
				
			||||||
    if (stack->i == -1) return (stackData){.ret_code = 1};
 | 
					    if (stack->i == -1) return (stackData){.ret_code = 1};
 | 
				
			||||||
    stackInput returnData;
 | 
					    stackInput returnData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (stack->type) {
 | 
					    switch (stack->type) {
 | 
				
			||||||
        case StringArray:
 | 
					        case StringArray:
 | 
				
			||||||
            returnData.string = stack->data.sarr[stack->i];
 | 
					            const size_t len = strlen(stack->data.sarr[stack->i]);
 | 
				
			||||||
            // todo might have to do malloc?
 | 
					            returnData.string = malloc(len * sizeof(char) + 1);
 | 
				
			||||||
            // todo ticking timebomb
 | 
					            strcpy(returnData.string, stack->data.sarr[stack->i]);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case CharArray:
 | 
					        case CharArray:
 | 
				
			||||||
            returnData.ch = stack->data.carr[stack->i];
 | 
					            returnData.ch = stack->data.carr[stack->i];
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user