/* EXERCISE 4-10 */ /* THE INPUT LINE line[] IS EXTERNAL TO ALL FUNCTIONS AS IS lp THE */ /* POINTER TO ITS ELEMENTS. THE ARRAY buf IS STILL USED, BUT ONLY */ /* TO STORE ENTIRE PUSHED-BACK STACK ELEMENTS. */ #include <stdio.h> #include <stdlib.h> /* FOR atof() */ #include <errno.h> #include <math.h> #define MAXLINE 1000 /* MAX INPUT LINE LENGTH */ #define MAXOP 100 /* MAX SIZE OF OPERAND OR OPERATOR */ #define NUMBER '0' /* SIGNAL THAT A NUMBER WAS FOUND */ #define PRINT '1' #define DUPLICATE '2' #define SWAP '3' #define CLEAR '4' #define SIN '5' #define COS '6' #define TAN '7' #define EXP '8' #define POW '9' #define SQRT 'A' #define VAR 'B' #define SETVAR 'C' #define PUSHBACK 'D' int lp; /* LINE POINTER */ char line[MAXLINE]; /* INPUT LINE AREA */ int getline(char [], int); int getop(char []); int validop(char []); void push(double); double pop(void); double rettop(void); void clear(void); double mod(double, double); void ftoarray(double, char []); void pushback(char []); /* REVERSE POLISH CALCULATOR */ main() { int i, type; double op1, op2, sqroot, power; double var[26]; double prtval = 0; char s[MAXOP]; char s2[MAXOP]; for (i = 0; i < 26; i++) var[i] = 0; while (getline(line, MAXLINE) > 0) { lp = 0; while ((type = getop(s)) != '\0') { errno = 0; switch (type) { case NUMBER: push(atof(s)); break; case '+': push(pop() + pop()); break; case '*': push(pop() * pop()); break; case '-': op2 = pop(); push(pop() - op2); break; case '/': op2 = pop(); if (op2 != 0.0) push(pop() / op2); else { printf("ERROR: ZERO DIVISOR\n"); return 0; } break; case '%': op2 = pop(); if (op2 != 0.0) { op1 = pop(); push(mod(op1, op2)); } else { printf("ERROR: ZERO DIVISOR\n"); return 0; } break; case '$': push(prtval); break; case '\n': printf("\t%.8g\n", prtval = pop()); break; case PRINT: /* PRINT TOP ELEMENT */ printf("\t%.8g\n", prtval = rettop()); break; case DUPLICATE: /* DUPLICATE TOP ELEMENT */ op1 = pop(); push(op1); push(op1); break; case SWAP: /* SWAP TOP TWO ELEMENTS */ op1 = pop(); op2 = pop(); push(op1); push(op2); break; case CLEAR: /* CLEAR THE STACK */ clear(); break; case SIN: push(sin(pop())); break; case COS: push(cos(pop())); break; case TAN: push(tan(pop())); break; case EXP: push(exp(pop())); break; case POW: op2 = pop(); op1 = pop(); power = pow(op1, op2); if (errno == EDOM) printf("ERROR: POW ARGUMENTS OUT OF RANGE: %g, %g\n", op1, op2); else if (errno == ERANGE) printf("ERROR: POW RESULT OUT OF RANGE\n"); else push(power); break; case SQRT: sqroot = sqrt(op1 = pop()); if (errno == EDOM) printf("ERROR: SQRT ARGUMENT OUT OF RANGE: %g\n", op1); else if (errno == ERANGE) printf("ERROR: SQRT RESULT OUT OF RANGE\n"); else push(sqroot); break; case VAR: /* PUSH VALUE OF VARIABLE */ push(var[s[0]-'a']); break; case SETVAR: /* ASSIGN VALUE TO VARIABLE */ var[s[0]-'a'] = rettop(); break; case PUSHBACK: /* PUSH TOP ELEMENT TO INPUT */ ftoarray(rettop(), s2); pushback(s2); break; default: printf("ERROR: UNKNOWN COMMAND %s\n", s); return 0; } } } printf("\nEND OF PROGRAM\n"); return 0; } /* GETLINE: GET LINE INTO s , RETURN LENGTH */ int getline(char s[], int lim) { int c, i; i = 0; while (--lim > 0 && (c=getchar()) != EOF && c != '\n') s[i++] = c; if (c == '\n') s[i++] = c; s[i] = '\0'; return i; } #define MAXVAL 100 /* MAXIMUM DEPTH OF VAL STACK */ int sp = 0; /* NEXT FREE STACK POSITION */ double val[MAXVAL]; /* VALUE STACK */ /* PUSH: PUSH f ONTO VALUE STACK */ void push(double f) { if (sp < MAXVAL) val[sp++] = f; else printf("ERROR: STACK FULL, CAN'T PUSH %g\n", f); } /* POP: POP AND RETURN TOP VALUE FROM STACK */ double pop(void) { if (sp > 0) return val[--sp]; else { printf("ERROR: STACK EMPTY\n"); return 0.0; } } /* RETTOP: RETURN TOP VALUE FROM STACK */ double rettop(void) { if (sp > 0) return val[sp - 1]; else { printf("ERROR: STACK EMPTY\n"); return 0.0; } } /* CLEAR: CLEAR THE STACK */ void clear(void) { sp = 0; } #include <ctype.h> int getch(void); void ungetch(int); /* GETOP: GET NEXT OPERATOR OR NUMERIC OPERAND */ int getop(char s[]) { int i, c, op; int setval = 0; int error = 0; while ((s[0] = c = getch()) == ' ' || c == '\t') ; s[1] = '\0'; i = 0; if (c == '=') { setval = 1; /* COLLECT EXPECTED ALPHA */ s[i] = c = getch(); /* OVERLAY '=' SIGN */ if (!isalpha(c)) { s[0] = '='; /* ALPHA MUST FOLLOW '=' SIGN */ s[1] = '\0'; return 'e'; } } if (isalpha(c)) { /* TEST FOR MULT CHAR OPERATOR */ while (isalpha(s[++i] = c = getch())) /* OR SINGLE CHAR VAR */ ; s[i] = '\0'; if (setval && i > 1) { s[0] = '='; /* VARIABLE NOT SINGLE CHAR ALPHA */ s[1] = '\0'; return 'e'; } if (c != ' ') /* NO NEED TO REREAD SPACES */ lp--; if ((op = validop(s)) == VAR && setval) op = SETVAR; return op; } if (!isdigit(c) && c != '.' && c != '(') return c; /* NOT A NUMBER - POSSIBLY EOF */ if (c == '(') { s[i] = '-'; /* CONVERT THE SIGN */ s[++i] = c = getch(); /* COLLECT DECIMAL OR FIRST DIGIT */ } if (isdigit(c)) /* COLLECT INTEGER PART */ while (isdigit(s[++i] = c = getch())) ; if (c == '.') /* COLLECT FRACTION PART */ while (isdigit(s[++i] = c = getch())) ; s[i] = '\0'; if (c != ' ' && c != ')') /* DON'T REREAD THE CLOSING ')' */ lp--; if (s[i-1] == '-') error = '('; /* NO NUMBER FOUND */ else if (s[i-1] == '.' && (i == 1 || !isdigit(s[i-2]))) error = '.'; /* NO NUMBER FOUND */ else if (s[0] == '-' && c != ')') error = '('; /* UNBALANCED PARENTHESES */ if (s[0] != '-' && c == ')') error = ')'; /* UNBALANCED PARENTHESES */ if (error) { s[0] = error; /* DISPLAY ERROR STRING */ s[1] = '\0'; return 'e'; } return NUMBER; } /* VALIDOP: TEST MULTI-CHAR ALPHA OPERATORS */ int validop(char s[]) { if ((s[0] >= 'A' && s[0] <= 'Z') && (s[1] == '\0')) { s[0] += 'a' - 'A'; return VAR; } if ((s[0] >= 'a' && s[0] <= 'z') && (s[1] == '\0')) return VAR; if ((s[0] == 'p' || s[0] == 'P') && (s[1] == 'r' || s[1] == 'R') && (s[2] == 't' || s[2] == 'T') && (s[3] == '\0')) return PRINT; if ((s[0] == 'd' || s[0] == 'D') && (s[1] == 'u' || s[1] == 'U') && (s[2] == 'p' || s[2] == 'P') && (s[3] == '\0')) return DUPLICATE; if ((s[0] == 's' || s[0] == 'S') && (s[1] == 'w' || s[1] == 'W') && (s[2] == 'p' || s[2] == 'P') && (s[3] == '\0')) return SWAP; if ((s[0] == 'c' || s[0] == 'C') && (s[1] == 'l' || s[1] == 'L') && (s[2] == 'r' || s[2] == 'R') && (s[3] == '\0')) return CLEAR; if ((s[0] == 's' || s[0] == 'S') && (s[1] == 'i' || s[1] == 'I') && (s[2] == 'n' || s[2] == 'N') && (s[3] == '\0')) return SIN; if ((s[0] == 'c' || s[0] == 'C') && (s[1] == 'o' || s[1] == 'O') && (s[2] == 's' || s[2] == 'S') && (s[3] == '\0')) return COS; if ((s[0] == 't' || s[0] == 'T') && (s[1] == 'a' || s[1] == 'A') && (s[2] == 'n' || s[2] == 'N') && (s[3] == '\0')) return TAN; if ((s[0] == 'e' || s[0] == 'E') && (s[1] == 'x' || s[1] == 'X') && (s[2] == 'p' || s[2] == 'P') && (s[3] == '\0')) return EXP; if ((s[0] == 'p' || s[0] == 'P') && (s[1] == 'o' || s[1] == 'O') && (s[2] == 'w' || s[2] == 'W') && (s[3] == '\0')) return POW; if ((s[0] == 's' || s[0] == 'S') && (s[1] == 'q' || s[1] == 'Q') && (s[2] == 'r' || s[2] == 'R') && (s[3] == 't' || s[3] == 'T') && (s[4] == '\0')) return SQRT; if ((s[0] == 'p' || s[0] == 'P') && (s[1] == 'b' || s[1] == 'B') && (s[2] == 'k' || s[2] == 'K') && (s[3] == '\0')) return PUSHBACK; return 'e'; } #define BUFSIZE 100 char buf[BUFSIZE]; /* BUFFER FOR ungetch */ int bufp = 0; /* NEXT FREE POSITION IN buf */ /* GETCH: GET A (POSSIBLY PUSHED BACK) CHARACTER */ int getch(void) { return (bufp > 0) ? buf[--bufp] : line[lp++]; } /* UNGETCH: PUSH CHARACTER BACK ON INPUT */ void ungetch(int c) { if (bufp >= BUFSIZE) printf("UNGETCH: TOO MANY CHARACTERS\n"); else buf[bufp++] = c; } /* MOD: COMPUTE THE MODULUS OF TWO DOUBLE PRECISION FLOATS */ /* DEFINED AS op1 - op2 * ((int) (op1 / op2)). */ /* HOWEVER, (op1/op2) MAY BE TO FOR A long int. */ /* - NOTE: THIS ROUTINE WILL NOT WORK FOR QUOTIENTS THAT OVERFLOW */ /* A TYPE double VARIABLE OR EQUAL THE MAXIMUM NEGATIVE VALUE. */ double mod(double op1, double op2) { double div, power, prod, whole; double abs1 = op1; double abs2 = op2; int digit; int sign = 1; /* CONVERT TO ABSOLUTE VALUES */ if (abs1 < 0.0) { abs1 *= -1; sign *= -1; } if (abs2 < 0.0) { abs2 *= -1; sign *= -1; } if (abs1 < abs2) return op1; div = abs1 / abs2; /* DETERMINE THE VALUE OF THE EXPONENT */ for (power = 1.0; div / (10.0 * power) >= 1.0; power *= 10.0) ; /* STRIP OFF THE WHOLE NUMBER PORTION OF THE QUOTIENT */ for (whole = 0.0; power >= 1.0 && div > 0.0; power /= 10) { digit = div / power; whole += (prod = digit * power); div -= prod; } return op1 - (op2 * sign * whole); } /* FTOARRAY: CONVERT FLOAT TO ARRAY */ void ftoarray(double f, char s[]) { double power; double prod; int digit; int decpt = 0; int i = 0; /* CONVERT TO ABSOLUTE VALUE */ if (f < 0.0) { f *= -1; s[i++] = '('; } /* DETERMINE THE VALUE OF THE EXPONENT */ for (power = 1.0; f / (10.0 * power) >= 1.0; power *= 10.0) ; /* STRIP OFF THE INDIVIDUAL DIGITS */ while (f > 0.0) { if (power == 0.1 && !decpt) { s[i++] = '.'; decpt = 1; } if (power < 1.0) { /* STRANGE DECIMAL ARITHMETIC */ power = 1.0; /* PROPERTIES MAKE THIS NECESSARY */ f *= 10.0; } digit = f / power; f -= digit * power; s[i++] = digit + '0'; power /= 10.0; } while (power >= 1.0) { /* FILL IN ALL WHOLE DIGITS */ s[i++] = '0'; power /= 10.0; } if (s[0] == '(') s[i++] = ')'; s[i] = '\0'; } void ungets(char []); /* PUSHBACK: PUSH TOP ELEMENT TO INPUT WITH A BLANK ON EITHER SIDE */ void pushback(char s[]) { ungetch(' '); ungets(s); ungetch(' '); } /* UNGETS: PUSH BACK A STRING ONTO THE INPUT */ void ungets(char s[]) { int i; for (i = strlen(s) - 1; i >= 0; i--) /* PUSH IT BACKWARDS */ ungetch(s[i]); }