Exercise 4.3 - RPN modulus operator and negative numbers#

Question#

Given the basic framework, it’s straightforward to extend the calculator. Add the modulus (%) operator and provisions for negative numbers.

/* Adding the Modulus operator and provision for negative numbers 
* Program is given the input in a single and and it print the output upon
* getting a \n character.
* For e.g:
*
* 10 10 + 100 + 2 *
*       240
*/

#include<stdio.h>
#include<stdlib.h>
#include<math.h>

#define MAXOP 100
#define NUMBER '0'

int getop(char []);
void push(double);
double pop(void);

/* reverse polish calculator */

int main(void)
{
    int type;
    double 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)
                            push(fmod(pop(),op2));
                        else
                            printf("erro:zero divisor\n");
                        break;
                case '\n':
                        printf("\t%.8g\n",pop());
                        break;
                default:
                        printf("error: unknown command %s\n",s);
                        break;

        }
    }
    return 0;
}


#define MAXVAL 100

int sp = 0;
double val[MAXVAL];

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;
    }
}

#include<ctype.h>

int getch(void);
void ungetch(int);

int getop(char s[]) {
    int i, c;
    while ((s[0] = c = getch()) == ' ' || c == '\t')
        ;
    s[1] = '\0';
    if (!isdigit(c) && c != '.' && c != '-')
        return c;       // not a number
    i = 0;
    if (c == '-' || isdigit(c))     // collect integer part along with '-'
        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 (strcmp(s, "-") == 0)
        return '-';
    return NUMBER;
}

#define BUFSIZE 100

char buf[BUFSIZE];
int bufp = 0;

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;
}

Explanation#

This program has number of helper functions like getop, push and pop, which we use to the implement the reverse polish notation calculator.

The function getop takes a string and determines if it is number. If it is a number, both integer or decimal, it will store that number in the array and return a flag NUMBER which states that number is found. It will push that number to the stack. If it getop returns an operator like +, -, * or /, it will pop two numbers out of the stack and operate on it. When it encounters a /, it ensures that the second operand is not 0 and disallows.

It pushes each number to the stack and when it finds an operand, it will pop out two numbers in the stack and operate on it and push the result back into the stack. When it encounters a n it will pop out the last stored number in the stack and gives the result.

Thus our operation of the RPN calculator for few inputs look like this.

10 10 + 100 + 2 *
        240
500 2 *
        1000
100 3 /
        33.333333
-10 -10 -
        0
20 -10 +
        10
-20 10 +
        -10
-10 -10 +
        -20