/* 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);
}