/* EXERCISE 4-11 */ /* MODIFIED VERSION OF EXERCISE 4-6 */ #include <stdio.h> #include <stdlib.h> /* FOR atof() */ #include <errno.h> #include <math.h> #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' int getop(char []); int validop(char []); void push(double); double pop(void); double rettop(void); void clear(void); double mod(double, double); /* REVERSE POLISH CALCULATOR */ main() { int i, type; double op1, op2, sqroot, power; double var[26]; double prtval = 0; char s[MAXOP]; for (i = 0; i < 26; i++) var[i] = 0; while ((type = getop(s)) != EOF) { 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; default: printf("ERROR: UNKNOWN COMMAND %s\n", s); return 0; } } printf("\nEND OF PROGRAM\n"); return 0; } #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); /* GETOP: GET NEXT OPERATOR OR NUMERIC OPERAND */ int getop(char s[]) { static int lastc = ' '; int i, c, op; int setval = 0; int error = 0; if (lastc != ' ' && lastc != '\t') { s[0] = c = lastc; lastc = ' '; } else 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 != EOF) lastc = c; 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 != EOF && c != ')') /* DON'T BUFFER THE CLOSING ')' */ lastc = c; 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; return 'e'; } /* GETCH: GET A (POSSIBLY PUSHED BACK) CHARACTER */ int getch(void) { return getchar(); } /* 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); }