Demo 3, tehtävä 3 ----------------- Muuta oheista rpncalc.c -ohjelmaa siten, että lausekkeissa voi käyttää useita muuttujia, joiden nimet ovat pienistä kirjaimista a-z muodostettuja merkkijonoja (rajoituksena vain pituus (jotain järkevää) ja tunnettujen funktioiden nimet, joita ei saa käyttää muuttujille). Korjaa samalla kaikki ohjelman bugit, myös järjettömien syötteiden aiheuttamista virheistä pitäisi tulla mielekäs virheilmoitus. /* 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 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 } }; typedef struct { enum { END, CONST, VAR, FUN1, FUN2 } type; union { double value; double (*f1)(double); double (*f2)(double, double); } u; } action; double evaluate(action *prog, double x) { double stack[MAXDEPTH]; double *stkp = stack; for ( ; ; ) { switch(prog->type) { case CONST: *++stkp = prog->u.value; break; case VAR: *++stkp = x; break; case FUN1: *stkp = prog->u.f1(*stkp); break; case FUN2: stkp--; *stkp = prog->u.f2(*(stkp+1), *stkp); break; case END: 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; case 'x': prog++->type=VAR; 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)) { fprintf(stderr, "Unknown funktion \"%s\"\n", name); exit(EXIT_FAILURE); } } while (strcmp(name,funcs[i].name)); *expr--=ch; prog->u.f1=funcs[i].fun; prog++->type=FUN1; 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 x, y; printf("rpn-lauseke (muuttuja x): "); fgets(expr, MAXLINE, stdin); compile(expr, prog); while (printf("x (q lopettaa): "), (scanf("%lf", &x))) { y=evaluate(prog, x); printf("y=%f\n", y); } return 0; }