#include "calculator.h" #include #include #include #include #include #define MAX_STACK_SIZE 256 #define MAX_TOKEN_LENGTH 100 typedef struct { double data[MAX_STACK_SIZE]; int top; } Stack; typedef struct { char data[MAX_STACK_SIZE][MAX_TOKEN_LENGTH]; int top; } StringStack; static void init_stack(Stack *s) { s->top = -1; } static bool is_stack_empty(Stack *s) { return s->top == -1; } static bool is_stack_full(Stack *s) { return s->top == MAX_STACK_SIZE - 1; } static void push(Stack *s, double value) { if (!is_stack_full(s)) { s->data[++s->top] = value; } } static double pop(Stack *s) { if (!is_stack_empty(s)) { return s->data[s->top--]; } return 0.0; } static void init_string_stack(StringStack *s) { s->top = -1; } static bool is_string_stack_empty(StringStack *s) { return s->top == -1; } static bool is_string_stack_full(StringStack *s) { return s->top == MAX_STACK_SIZE - 1; } static void push_string(StringStack *s, const char *str) { if (!is_string_stack_full(s) && strlen(str) < MAX_TOKEN_LENGTH) { strcpy(s->data[++s->top], str); } } static char* pop_string(StringStack *s) { if (!is_string_stack_empty(s)) { return s->data[s->top--]; } return NULL; } static char* peek_string(StringStack *s) { if (!is_string_stack_empty(s)) { return s->data[s->top]; } return NULL; } bool is_operator(char c) { return c == '+' || c == '-' || c == '*' || c == '/' || c == '^'; } int get_priority(char op) { switch (op) { case '+': case '-': return 1; case '*': case '/': return 2; case '^': return 3; default: return 0; } } bool is_function(const char *str, int *length) { if (strncmp(str, "sin", 3) == 0) { *length = 3; return true; } if (strncmp(str, "cos", 3) == 0) { *length = 3; return true; } if (strncmp(str, "sqrt", 4) == 0) { *length = 4; return true; } if (strncmp(str, "log", 3) == 0) { *length = 3; return true; } return false; } double apply_operator(double a, double b, char op) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': if (b == 0) { return NAN; } return a / b; case '^': return pow(a, b); default: return NAN; } } double apply_function(const char *func, double value, bool *error) { if (strcmp(func, "sin") == 0) { return sin(value); } if (strcmp(func, "cos") == 0) { return cos(value); } if (strcmp(func, "sqrt") == 0) { if (value < 0) { *error = true; return NAN; } return sqrt(value); } if (strcmp(func, "log") == 0) { if (value <= 0) { *error = true; return NAN; } return log10(value); } *error = true; return NAN; } static char** infix_to_postfix(const char *expression, int *token_count, bool *error) { StringStack operator_stack; init_string_stack(&operator_stack); char **output = malloc(MAX_STACK_SIZE * sizeof(char*)); for (int i = 0; i < MAX_STACK_SIZE; i++) { output[i] = malloc(MAX_TOKEN_LENGTH * sizeof(char)); } *token_count = 0; *error = false; int i = 0; int len = strlen(expression); while (i < len) { if (isspace(expression[i])) { i++; continue; } if (isdigit(expression[i]) || expression[i] == '.') { int j = 0; char num[MAX_TOKEN_LENGTH] = {0}; while (i < len && (isdigit(expression[i]) || expression[i] == '.')) { num[j++] = expression[i++]; } num[j] = '\0'; strcpy(output[(*token_count)++], num); continue; } int func_len; if (is_function(expression + i, &func_len)) { char func[10] = {0}; strncpy(func, expression + i, func_len); func[func_len] = '\0'; i += func_len; push_string(&operator_stack, func); continue; } if (is_operator(expression[i])) { while (!is_string_stack_empty(&operator_stack)) { char *top = peek_string(&operator_stack); if (strcmp(top, "(") != 0 && get_priority(top[0]) >= get_priority(expression[i]) && strlen(top) == 1) { strcpy(output[(*token_count)++], pop_string(&operator_stack)); } else { break; } } char op[2] = {expression[i++], '\0'}; push_string(&operator_stack, op); continue; } if (expression[i] == '(') { char bracket[2] = {expression[i++], '\0'}; push_string(&operator_stack, bracket); continue; } if (expression[i] == ')') { i++; while (!is_string_stack_empty(&operator_stack) && strcmp(peek_string(&operator_stack), "(") != 0) { strcpy(output[(*token_count)++], pop_string(&operator_stack)); } if (is_string_stack_empty(&operator_stack)) { *error = true; break; } pop_string(&operator_stack); if (!is_string_stack_empty(&operator_stack)) { char *top = peek_string(&operator_stack); if (is_function(top, &func_len)) { strcpy(output[(*token_count)++], pop_string(&operator_stack)); } } continue; } *error = true; break; } while (!is_string_stack_empty(&operator_stack)) { char *top = peek_string(&operator_stack); if (strcmp(top, "(") == 0) { *error = true; break; } strcpy(output[(*token_count)++], pop_string(&operator_stack)); } if (*error) { for (int j = 0; j < MAX_STACK_SIZE; j++) { free(output[j]); } free(output); return NULL; } return output; } static double evaluate_postfix(char **tokens, int token_count, bool *error) { Stack value_stack; init_stack(&value_stack); for (int i = 0; i < token_count; i++) { char *token = tokens[i]; if (isdigit(token[0]) || (token[0] == '.' && isdigit(token[1]))) { push(&value_stack, atof(token)); continue; } int func_len; if (is_function(token, &func_len)) { if (is_stack_empty(&value_stack)) { *error = true; return NAN; } double value = pop(&value_stack); double result = apply_function(token, value, error); if (*error) { return NAN; } push(&value_stack, result); continue; } if (is_operator(token[0]) && strlen(token) == 1) { if (is_stack_empty(&value_stack)) { *error = true; return NAN; } double b = pop(&value_stack); if (is_stack_empty(&value_stack)) { *error = true; return NAN; } double a = pop(&value_stack); double result = apply_operator(a, b, token[0]); if (isnan(result)) { *error = true; return NAN; } push(&value_stack, result); continue; } *error = true; return NAN; } if (is_stack_empty(&value_stack)) { *error = true; return NAN; } double result = pop(&value_stack); if (!is_stack_empty(&value_stack)) { *error = true; return NAN; } return result; } double evaluate_expression(const char *expression, bool *error) { *error = false; if (expression == NULL || strlen(expression) == 0) { *error = true; return NAN; } int token_count; char **postfix_tokens = infix_to_postfix(expression, &token_count, error); if (*error || postfix_tokens == NULL) { *error = true; return NAN; } double result = evaluate_postfix(postfix_tokens, token_count, error); for (int i = 0; i < MAX_STACK_SIZE; i++) { free(postfix_tokens[i]); } free(postfix_tokens); return result; }