Exercise 4.5 - RPN Calculator with mathematical functions¶
Question¶
Add access to library functions like sin, exp, and pow.
/**
* compile with -lm flag(the static math library)
**/
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXOP 100
#define NUMBER '0'
#define NAME 'n'
#define BUFSIZE 100
#define MAXVAL 100
int sp = 0;
double val[MAXVAL];
char buf[BUFSIZE];
int bufp = 0;
int getch(void);
void ungetch(int);
int getop(char[]);
void push(double);
double pop(void);
void mathfnc(char[]);
/* reverse polish calculator */
int main(void) {
int type;
double op2, op1;
char s[MAXOP];
void clearsp(void);
while ((type = getop(s)) != EOF) {
switch (type) {
case NUMBER:
push(atof(s));
break;
case NAME:
mathfnc(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");
break;
case '%':
op2 = pop();
if (op2 != 0.0)
push(fmod(pop(), op2));
else
printf("erro:zero divisor\n");
break;
case '?':
op2 = pop();
printf("\t%.8g\n", op2);
push(op2);
break;
case 'c':
clearsp();
break;
case 'd':
op2 = pop();
push(op2);
push(op2);
break;
case 's':
op1 = pop();
op2 = pop();
push(op1);
push(op2);
break;
case '\n':
printf("\t%.8g\n", pop());
break;
default:
printf("error: unknown command %s\n", s);
break;
}
}
return 0;
}
void push(double f) {
if (sp < MAXVAL)
val[sp++] = f;
else
printf("error:stack full, cant push %g\n", f);
}
double pop(void) {
if (sp > 0)
return val[--sp];
else {
printf("error: stack empty\n");
return 0.0;
}
}
void clearsp(void) { sp = 0; }
int getop(char s[]) {
int i, c;
while ((s[0] = c = getch()) == ' ' || c == '\t');
s[1] = '\0';
i = 0;
if (islower(c)) {
while (islower(s[++i] = c = getch()));;
s[i] = '\0';
if (c != EOF)
ungetch(c);
if (strlen(s) > 1)
return NAME;
else
/*return c; this line was bad since when s < 1, the array s only has
one character s[0], therofore, this character must be retorned in
order to see if it is d,?,s etc. The character c instead contain
whatever non-lower value wich always will result in a command
uknown*/
return s[0];
}
if (!isdigit(c) && c != '.' && c != '-')
return c;
if (c == '-')
if (isdigit(c = getch()) || c == '.')
s[++i] = c;
else {
if (c != EOF)
ungetch(c);
return '-';
}
if (isdigit(c))
while (isdigit(s[++i] = c = getch()));
if (c == '.')
while (isdigit(s[++i] = c = getch()));
s[i] = '\0';
if (c != EOF)
ungetch(c);
return NUMBER;
}
int getch(void) { return (bufp > 0) ? buf[--bufp] : getchar(); }
void ungetch(int c) {
if (bufp >= BUFSIZE)
printf("ungetch: too many characters\n");
else
buf[bufp++] = c;
}
/* mathfnc: check the string s for supported math function */
void mathfnc(char s[]) {
double op2;
if (strcmp(s, "sin") == 0)
push(sin(pop()));
else if (strcmp(s, "cos") == 0)
push(cos(pop()));
else if (strcmp(s, "exp") == 0)
push(exp(pop()));
else if (strcmp(s, "pow") == 0) {
op2 = pop();
push(pow(pop(), op2));
} else
printf("error: %s is not supported\n", s);
}
Explanation¶
The RPN calculator has addition features like doing mathematical functions. In the input, if a string is given then the calculator identifies it as a NAME and goes to the mathfun.
In the mathfun, the string input is compared with “sin” and if it is a sin, the mathematical function sin is called on the popped value. If the intput is cos, the cosine function is called and if the input is “pow”, then first value is popped and stored in op2 and second value is raised to the power of op2.
The curx of program is in this function.
void mathfnc(char s[])
{
double op2;
if(strcmp(s,"sin")==0)
push(sin(pop()));
else if(strcmp(s,"cos")==0)
push(cos(pop()));
else if(strcmp(s,"exp")==0)
push(exp(pop()));
else if(strcmp(s,"pow")==0)
{
op2 = pop();
push(pow(pop(),op2));
}
else
printf("error: %s is not supported\n",s);
}