/* RPN-laskin: * laskee RPN-muodossa annettuja lausekkeita * esim. "X5+6* sin" = sin((x+5)*6" jne * * Ei kommentteja eikä liikaa tarkistuksia, * eikä muutenkaan esimerkki hyvästä koodaustavasta * vaan koodinlukuharjoitus. :-) * * Huom. käännös edellyttää matematiikkakirjaston linkitystä mukaan: * * cc -o rpncalc rpncalc.c -lm */ #include #include #include #include #define MAXLINE 100 #define MAXOPS 100 #define MAXDEPTH 100 #define MAXVARNAME 10 double add(double x, double y) { return x+y; } double subtract(double x, double y) { return x-y; } double multiply(double x, double y) { return x*y; } double divide(double x, double y) { return x/y; } double (*opers[])(double,double) = { add, subtract, multiply, divide }; char optable[] = "+-*/"; struct { double (*fun)(double); char *name; } funcs[] = { { sin, "sin" }, { cos, "cos" }, { tan, "tan" }, { asin, "asin" }, { acos, "acos" }, { atan, "atan" }, { sqrt, "sqrt" }, { 0, 0 } }; struct { char name[MAXVARNAME]; double value; } variables[MAXLINE]; static int variablecount = -1; typedef struct { enum { END, CONST, VAR, FUN1, FUN2 } type; union { double value; double *var; double (*f1)(double); double (*f2)(double, double); } u; } action; double evaluate(action *prog) { double stack[MAXDEPTH]; double *stkp = stack; for ( ; ; ) { switch(prog->type) { case CONST: if (stkp >= stack+MAXDEPTH-1) { fprintf(stderr, "ERROR: stack overflow\n"); exit(1); } *++stkp = prog->u.value; break; case VAR: if (stkp >= stack+MAXDEPTH-1) { fprintf(stderr, "ERROR: stack overflow\n"); exit(1); } *++stkp = *(prog->u.var); break; case FUN1: *stkp = prog->u.f1(*stkp); break; case FUN2: if (stkp == stack) { fprintf(stderr, "ERROR: stack underflow\n"); exit(1); } stkp--; *stkp = prog->u.f2(*(stkp+1), *stkp); break; case END: if (stkp > stack+1) { fprintf(stderr, "Warning: %ld unused values left in stack\n", stkp-stack-1); } return *stkp; } prog++; } } void compile(char *expr, action *prog) { double num; char ch, *name; int i; for (;*expr; expr++) { switch(ch=*expr) { case ' ': case '\n': case '\t': continue; case '+': case '-': case '*': case '/': prog->u.f2=opers[strchr(optable,ch)-optable]; prog++->type=FUN2; continue; } if ('a'<=ch && ch<='z') { name=expr; do { ch = *++expr; } while ('a'<=ch && ch<='z'); *expr='\0'; i=-1; do { if (!(funcs[++i].name)) { goto variable; } } while (strcmp(name,funcs[i].name)); *expr--=ch; prog->u.f1=funcs[i].fun; prog++->type=FUN1; continue; variable: i=-1; do { if (++i >= variablecount) { strcpy(variables[i=++variablecount].name, name); break; } } while (strcmp(name,variables[i].name)); *expr--=ch; prog->u.var= &variables[i].value; prog++->type=VAR; continue; } if (('0'<=ch && ch<='9') || ch=='-' || ch=='.') { name=expr; do { ch = *++expr; } while (('0'<=ch && ch<='9') || ch=='.' || ch=='e'); *expr='\0'; sscanf(name, "%lf", &num); *expr--=ch; prog->u.value=num; prog++->type=CONST; continue; } printf("Invalid character '%c'\n", ch); exit(EXIT_FAILURE); } prog->type=END; } int main() { char expr[MAXLINE+1]; action prog[MAXOPS]; double y; int i; printf("rpn-lauseke: "); fgets(expr, MAXLINE, stdin); compile(expr, prog); printf("%d variables\n", 1+variablecount); do { printf("Enter variable values (q to quit)\n"); for (i=0; i<=variablecount; ++i) { printf("%s: ", variables[i].name); if (1!=scanf("%lf", &variables[i].value)) exit(0); } y=evaluate(prog); printf("Result = %f\n", y); } while (variablecount>-1); return 0; }