#include "calculator.h" #include #include #include #include #include /* ---------------------------- */ /* - globalna chyba */ /* ---------------------------- */ static char g_err[128] = "OK"; /* - helper: set error */ static void set_err(const char *msg) { strncpy(g_err, msg, sizeof(g_err)-1); } /* - vrat error text */ const char *calc_error(void) { return g_err; } /* ---------------------------- */ /* - token typy */ /* ---------------------------- */ typedef enum { T_NUM, /* - cislo */ T_OP, /* - operator */ T_FUNC, /* - funkcia */ T_LP, /* - ( */ T_RP /* - ) */ } TType; typedef struct { TType type; double num; /* - hodnota */ char op; /* - + - * / ^ ~ */ char func[8]; /* - sin cos sqrt log ln */ } Token; /* ---------------------------- */ /* - jednoduche pole tokenov */ /* ---------------------------- */ typedef struct { Token *a; int n; int cap; } TVec; /* - init */ static void tvec_init(TVec *v) { v->a=NULL; v->n=0; v->cap=0; } /* - free */ static void tvec_free(TVec *v) { free(v->a); tvec_init(v); } /* - push */ static int tvec_push(TVec *v, Token t) { if (v->n >= v->cap) { int nc = v->cap ? v->cap*2 : 32; Token *p = realloc(v->a, nc*sizeof(Token)); if (!p) return 0; v->a = p; v->cap = nc; } v->a[v->n++] = t; return 1; } /* ---------------------------- */ /* - priorita operatorov */ /* ---------------------------- */ static int prec(char op) { if (op=='~') return 4; /* - unarne minus */ if (op=='^') return 3; /* - mocnina */ if (op=='*' || op=='/') return 2; /* - nasob/del */ if (op=='+' || op=='-') return 1; /* - plus/minus */ return -1; } /* - prava asociativita */ static int right_assoc(char op) { return (op=='^' || op=='~'); /* - pow, unary */ } /* ---------------------------- */ /* - tokenize: string -> tokeny */ /* ---------------------------- */ static int tokenize(const char *s, TVec *out) { /* - reset error */ set_err("OK"); tvec_init(out); /* - prev token */ TType prev = T_OP; /* - na zaciatku */ while (*s) { /* - skip spaces */ while (isspace((unsigned char)*s)) s++; if (!*s) break; /* ---------------------------- */ /* - cislo */ /* ---------------------------- */ if (isdigit((unsigned char)*s) || *s=='.') { char *end = NULL; double x = strtod(s, &end); if (end==s) { set_err("Zle cislo"); return 0; } Token t = {0}; t.type = T_NUM; t.num = x; if (!tvec_push(out, t)) { set_err("No memory"); return 0; } s = end; prev = T_NUM; continue; } /* ---------------------------- */ /* - ident: funkcia/konstanta */ /* ---------------------------- */ if (isalpha((unsigned char)*s)) { char buf[16]={0}; int i=0; while (isalpha((unsigned char)*s) && i<15) { buf[i++] = (char)tolower((unsigned char)*s); s++; } buf[i]=0; /* - konstanta pi */ if (!strcmp(buf,"pi")) { Token t={0}; t.type=T_NUM; t.num=M_PI; if (!tvec_push(out,t)) { set_err("No memory"); return 0; } prev=T_NUM; continue; } /* - konstanta e */ if (!strcmp(buf,"e")) { Token t={0}; t.type=T_NUM; t.num=M_E; if (!tvec_push(out,t)) { set_err("No memory"); return 0; } prev=T_NUM; continue; } /* - funkcie */ if (!strcmp(buf,"sin") || !strcmp(buf,"cos") || !strcmp(buf,"sqrt") || !strcmp(buf,"log") || !strcmp(buf,"ln")) { Token t={0}; t.type=T_FUNC; strncpy(t.func, buf, sizeof(t.func)-1); if (!tvec_push(out,t)) { set_err("No memory"); return 0; } prev=T_FUNC; continue; } set_err("Neznama funkcia"); return 0; } /* ---------------------------- */ /* - zatvorky */ /* ---------------------------- */ if (*s=='(') { Token t={0}; t.type=T_LP; if (!tvec_push(out,t)) { set_err("No memory"); return 0; } s++; prev=T_LP; continue; } if (*s==')') { Token t={0}; t.type=T_RP; if (!tvec_push(out,t)) { set_err("No memory"); return 0; } s++; prev=T_RP; continue; } /* ---------------------------- */ /* - operatory */ /* ---------------------------- */ if (strchr("+-*/^", *s)) { char op = *s; /* - unary minus */ if (op=='-' && !(prev==T_NUM || prev==T_RP)) { op='~'; } Token t={0}; t.type=T_OP; t.op=op; if (!tvec_push(out,t)) { set_err("No memory"); return 0; } s++; prev=T_OP; continue; } set_err("Neplatny znak"); return 0; } if (out->n==0) { set_err("Prazdny vyraz"); return 0; } return 1; } /* ---------------------------- */ /* - infix -> postfix */ /* ---------------------------- */ static int to_postfix(const TVec *in, TVec *out) { tvec_init(out); TVec st; /* - operator stack */ tvec_init(&st); for (int i=0;in;i++) { Token t = in->a[i]; /* - cislo -> output */ if (t.type==T_NUM) { if (!tvec_push(out,t)) { set_err("No memory"); goto fail; } } /* - funkcia -> stack */ else if (t.type==T_FUNC) { if (!tvec_push(&st,t)) { set_err("No memory"); goto fail; } } /* - operator */ else if (t.type==T_OP) { while (st.n>0) { Token top = st.a[st.n-1]; /* - funkcia ma prioritu */ if (top.type==T_FUNC) { if (!tvec_push(out,top)) { set_err("No memory"); goto fail; } st.n--; continue; } /* - operator priorita */ if (top.type==T_OP) { int p1 = prec(t.op); int p2 = prec(top.op); /* - pop pri vacsej priorite */ if (p2>p1 || (p2==p1 && !right_assoc(t.op))) { if (!tvec_push(out,top)) { set_err("No memory"); goto fail; } st.n--; continue; } } break; } if (!tvec_push(&st,t)) { set_err("No memory"); goto fail; } } /* - ( -> stack */ else if (t.type==T_LP) { if (!tvec_push(&st,t)) { set_err("No memory"); goto fail; } } /* - ) -> pop do ( */ else if (t.type==T_RP) { int ok=0; while (st.n>0) { Token top = st.a[--st.n]; if (top.type==T_LP) { ok=1; break; } if (!tvec_push(out,top)) { set_err("No memory"); goto fail; } } if (!ok) { set_err("Zle zatvorky"); goto fail; } /* - po zatvorke funkcia */ if (st.n>0 && st.a[st.n-1].type==T_FUNC) { Token f = st.a[--st.n]; if (!tvec_push(out,f)) { set_err("No memory"); goto fail; } } } } /* - pop zvysok */ while (st.n>0) { Token top = st.a[--st.n]; if (top.type==T_LP) { set_err("Zle zatvorky"); goto fail; } if (!tvec_push(out,top)) { set_err("No memory"); goto fail; } } tvec_free(&st); return 1; fail: tvec_free(&st); tvec_free(out); return 0; } /* ---------------------------- */ /* - stack double */ /* ---------------------------- */ typedef struct { double *a; int n; int cap; } DStack; static void ds_init(DStack *s){ s->a=NULL; s->n=0; s->cap=0; } static void ds_free(DStack *s){ free(s->a); ds_init(s); } static int ds_push(DStack *s, double x){ if (s->n>=s->cap){ int nc=s->cap? s->cap*2:32; double *p=realloc(s->a,nc*sizeof(double)); if(!p) return 0; s->a=p; s->cap=nc; } s->a[s->n++]=x; return 1; } static int ds_pop(DStack *s, double *x){ if(s->n==0) return 0; *x=s->a[--s->n]; return 1; } /* ---------------------------- */ /* - apply function */ /* ---------------------------- */ static int apply_func(const char *f, double x, double *out){ if(!strcmp(f,"sin")) { *out=sin(x); return 1; } if(!strcmp(f,"cos")) { *out=cos(x); return 1; } if(!strcmp(f,"sqrt")){ if(x<0) { set_err("sqrt domena"); return 0; } *out=sqrt(x); return 1; } if(!strcmp(f,"log")){ if(x<=0) { set_err("log domena"); return 0; } *out=log10(x); return 1; } if(!strcmp(f,"ln")){ if(x<=0) { set_err("ln domena"); return 0; } *out=log(x); return 1; } set_err("Zla funkcia"); return 0; } /* ---------------------------- */ /* - eval postfix */ /* ---------------------------- */ static int eval_postfix(const TVec *post, double *out){ DStack st; ds_init(&st); for(int i=0;in;i++){ Token t=post->a[i]; /* - cislo -> push */ if(t.type==T_NUM){ if(!ds_push(&st,t.num)){ set_err("No memory"); goto fail; } } /* - funkcia */ else if(t.type==T_FUNC){ double a,r; if(!ds_pop(&st,&a)){ set_err("Syntax"); goto fail; } if(!apply_func(t.func,a,&r)) goto fail; if(!ds_push(&st,r)){ set_err("No memory"); goto fail; } } /* - operator */ else if(t.type==T_OP){ /* - unary minus */ if(t.op=='~'){ double a; if(!ds_pop(&st,&a)){ set_err("Syntax"); goto fail; } if(!ds_push(&st,-a)){ set_err("No memory"); goto fail; } continue; } /* - binarne */ double b,a,r; if(!ds_pop(&st,&b) || !ds_pop(&st,&a)){ set_err("Syntax"); goto fail; } if(t.op=='+') r=a+b; else if(t.op=='-') r=a-b; else if(t.op=='*') r=a*b; else if(t.op=='/'){ if(b==0){ set_err("Delenie nulou"); goto fail; } r=a/b; } else if(t.op=='^'){ r=pow(a,b); if(isnan(r) || isinf(r)){ set_err("Pow domena"); goto fail; } } else { set_err("Zly operator"); goto fail; } if(!ds_push(&st,r)){ set_err("No memory"); goto fail; } } else{ set_err("Syntax"); goto fail; } } /* - musi ostat 1 */ if(st.n!=1){ set_err("Syntax"); goto fail; } *out=st.a[0]; ds_free(&st); return 1; fail: ds_free(&st); return 0; } /* ---------------------------- */ /* - hlavna funkcia */ /* ---------------------------- */ calc_status_t calc_evaluate(const char *expr, double *out){ if(!expr || !out){ set_err("NULL"); return CALC_ERR; } TVec toks, post; tvec_init(&toks); tvec_init(&post); /* - tokenize */ if(!tokenize(expr,&toks)){ tvec_free(&toks); return CALC_ERR; } /* - postfix */ if(!to_postfix(&toks,&post)){ tvec_free(&toks); return CALC_ERR; } /* - eval */ if(!eval_postfix(&post,out)){ tvec_free(&toks); tvec_free(&post); return CALC_ERR; } tvec_free(&toks); tvec_free(&post); return CALC_OK; }