This exercise is the start of a series of exercises that revolve around modifying the calculator program, so for these next few exercises, we will use the code from the previous exercise as a starting point to add functionality to.
Currently, when getop
comes across anything other than a
digit or a decimal point, it returns from the function. The first thing
we need to do is make sure that the function does not return
immediately for +
or -
either. Then, at the
end of getop
, if i is equal to one, which
happens if there were no digits afterward, then we know that the
operator itself was intended and so we return it instead. Note that
atof
will automatically deal with the leading
+
or -
.
...
/* getop: get next operator or numeric operand */
int getop(char s[])
{
int i, c;
while ((s[0] = c = getch()) == ' ' || c == '\t')
;
s[1] = '\0';
if (!isdigit(c) && c != '.' && c != '+' && c != '-')
return c; /* not a number */
i = 0;
if (isdigit(c) || c == '+' || 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)
ungetch(c);
if ((s[0] == '+' || s[0] == '-') && i == 1)
return s[0]; /* return operator if no digits afterwards */
return NUMBER;
}
...
For the modulo operation, one might think that we could use the
standard %
operator, but that would be forgetting one
thing: %
does not work on floating-point values. One
solution would be to use fmod
from
<math.h>
, but seeing as the function is fairly easy
to implement, let us try doing it ourselves. All we need to do is to
repeatedly subtract the second operator from the first until
subtracting would mean the first operator would be less than zero. For
this, we will also need to pop
the first operator and
store it into op1. Finally, similar to division, we need to
make sure that op2 is not equal to zero.
...
/* reverse Polish calculator */
main()
{
int type;
double op1, op2;
char s[MAXOP];
while ((type = getop(s)) != EOF) {
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");
break;
case '%':
op2 = pop();
if (op2 != 0.0) {
for (op1 = pop(); op1 >= op2; op1 -= op2)
;
push(op1);
} else
printf("error: zero divisor\n");
break;
case '\n':
printf("\t%.8g\n", pop());
break;
default:
printf("error: unknown command %s\n", s);
break;
}
}
return 0;
}
...