usaa25/sk2/calculator.c
2026-01-25 15:52:25 +01:00

198 lines
5.8 KiB
C

#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <stdbool.h>
#include "calculator.h"
#include <string.h>
#include <stdlib.h>
#define MAX_TOKEN_LEN 256
typedef enum{
TOKEN_NUMBER,
TOKEN_FUNCTION,
TOKEN_OPERATOR,
TOKEN_LPAREN,
TOKEN_RPAREN,
TOKEN_UNKNOWN
} TokenType;
typedef struct{
TokenType type;
char value[MAX_TOKEN_LEN];
} Token;
static int get_precedence(const char *op){
if (strcmp(op,"+")==0||strcmp(op,"-")==0) return 1;
if (strcmp(op,"*")==0||strcmp(op,"/")==0) return 2;
if (strcmp(op,"^2")==0) return 3;
if (strcmp(op,"sin")==0||strcmp(op,"cos")==0||strcmp(op,"sqrt")==0||strcmp(op,"log")==0) return 4;
return 0;
}
static bool is_right_associative(const char *op){
return strcmp(op,"^2")==0;
}
static int tokenize(const char *expr, Token *tokens, int max_tokens){
int count= 0;
const char *p = expr;
while(*p){
if(isspace(*p)){p++; continue;}
if(isdigit(*p)||*p=='.'||(*p=='-'&&(isdigit(p[1])||p[1]=='.'))){
char *end;
strtod(p,&end);
strncpy(tokens[count].value, p ,end-p);
tokens[count].value[end-p] = '\0';
tokens[count].type = TOKEN_NUMBER;
p = end;
// p++;
}
else if(*p=='('){
strcpy(tokens[count].value, "(");
tokens[count].type = TOKEN_LPAREN;
p++;
}
else if(*p==')'){
strcpy(tokens[count].value, ")");
tokens[count].type = TOKEN_RPAREN;
p++;
}
else if(isalpha(*p)){
char func[5];
int i =0;
while(isalpha(*p)&&i<4){func[i++]=*p++;};
func[i] = '\0';
if (strcmp(func,"cos")==0||strcmp(func,"sin")==0||strcmp(func,"sqrt")==0||strcmp(func,"log")==0){
strcpy(tokens[count].value, func);
tokens[count].type = TOKEN_FUNCTION;
}
else{ return -1;}
}
else{
char op[3];
op[0] = *p;
op[1] = '\0';
if (*p == '^' &&p[1]=='2'){
strcpy(op,"^2");
p+=2;
}
p++;
strcpy(tokens[count].value, op);
tokens[count].type = TOKEN_OPERATOR;
}
count++;
if (count>=max_tokens) return -1;
}
return count;
}
static int infix_to_postfix(Token *infix, int infix_count, Token *postfix){
Token op_stack[MAX_TOKEN_LEN];
int on_top = -1;
int postfix_count = 0;
for (int i = 0; i<infix_count;i++){
Token t = infix[i];
switch(t.type){
case TOKEN_NUMBER:
postfix[postfix_count++] = t;
break;
case TOKEN_FUNCTION:
op_stack[++on_top] = t;
break;
case TOKEN_OPERATOR:
while(on_top>=0){
Token top = op_stack[on_top];
if(top.type!=TOKEN_OPERATOR&&top.type!=TOKEN_FUNCTION) break;
int prec_t = get_precedence(t.value);
int prec_top = get_precedence(top.value);
if(prec_top<prec_t||(prec_t==prec_top&&!is_right_associative(t.value))) break;
postfix[postfix_count++] = op_stack[on_top--];
}
op_stack[++on_top] = t;
break;
case TOKEN_LPAREN:
op_stack[++on_top] = t;
break;
case TOKEN_RPAREN:
while (on_top>=0&&strcmp(op_stack[on_top].value,"(")!=0){
postfix[postfix_count++] = op_stack[on_top--];
}
if (on_top<0) return -1;
on_top--;
break;
default:
return -1;
}
}
while(on_top>=0){
if(strcmp(op_stack[on_top].value,"(")==0) return -1;
postfix[postfix_count++] = op_stack[on_top--];
}
return postfix_count;
}
static double evaluate_postfix(Token *postfix, int count){
double stack[MAX_TOKEN_LEN];
int top= -1;
for (int i = 0; i<count; i++){
Token t =postfix[i];
if (t.type == TOKEN_NUMBER){
stack[++top] = atof(t.value);
}
else{
if (t.type == TOKEN_FUNCTION|| (strcmp(t.value,"^2")==0)){
if (top<0) return NAN;
double a= stack[top--];
if(strcmp(t.value, "cos")==0) stack[++top] = cos(a);
else if(strcmp(t.value, "sin")==0) stack[++top] = sin(a);
else if(strcmp(t.value, "sqrt")==0){
if (a<0) return NAN;
stack[++top] = sqrt(a);
}
else if(strcmp(t.value, "log")==0){
if (a<=0) return NAN;
stack[++top] = log(a);
}
else if(strcmp(t.value,"^2")==0) stack[++top] = a*a;
else return NAN;
}
else{
if (top<1) return NAN;
double b = stack[top--];
double a = stack[top--];
if (strcmp(t.value,"+")==0) stack[++top] = a+b;
else if (strcmp(t.value,"-")==0) stack[++top] = a-b;
else if (strcmp(t.value,"*")==0) stack[++top] = a*b;
else if (strcmp(t.value,"/")==0){
if (b==0) return NAN;
stack[++top] = a/b;
}
}
}
}
if (top!=0) return NAN;
return stack[0];
}
double evaluate(const char *expression){
Token infix[MAX_TOKEN_LEN];
int infix_count = tokenize(expression, infix,MAX_TOKEN_LEN);
if (infix_count<0) return NAN;
Token postfix[MAX_TOKEN_LEN];
int postfix_count = infix_to_postfix(infix,infix_count,postfix);
if (postfix_count<0) return NAN;
return evaluate_postfix(postfix, postfix_count);
}