Exercise 4-3

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

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