Exercise 4.11 - getline using static

Question

Modify getop so that it doesn’t need to use ungetch. Hint: use an internal static variable.

/**
 * Exercise 4.11 of The C Programming Language by Brian Kernighan and Dennis
 * Ritchie
 *
 * Modify getop so that it doesn't need to use ungetch. Hint: use an internal
 * static variable.
 *
 */

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h> // for atof()

#define NUMBER '0'
#define MAXOP 100

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

/* reverse Polish calculator */

int main(int argc, char *argv[]) {
    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((int)pop() % (int)op2);
            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;
}

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

#include <ctype.h>

int getch(void);

int getop(char s[]) {
    int c, i;
    static int lastc = 0;

    if (lastc == 0)
        c = getch();
    else {
        c = lastc;
        lastc = 0;
    }

    while ((s[0] = c) == ' ' || c == '\t')
        c = getch();

    s[1] = '\0';
    if (!isdigit(c) && c != '.')
        return c; /* not a number */

    i = 0;
    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)
        lastc = c;
    return NUMBER;
}

#define BUFSIZE 100

char buf[BUFSIZE]; /* buffer for ungetch */
int bufp = 0;      /* next free position in buf */

int getch(void) /* get a (possibly pushed back) character */
{
    return (bufp > 0) ? buf[--bufp] : getchar();
}

Explanation

The point of illustration of this program is the static variable, lastc, which gets initialized once as a static variable and maintains its state at each invocation. The getop function declares the variable lastc and proceeds as before. It calles getch to get the last character and if it is a EOF it returns the EOF, if it a space ignores and if not a number, it returns immediately and ensures that it parses a valid number.

At the end, it verifies that the character read is not EOF and the stores the last character which was read using getch in the lastc variable.

int getop(char s[])
{
        int c,i;
        static int lastc = 0;

        if(lastc == 0)
                c = getch();
        else
        {
                c = lastc;
                lastc = 0;
        }

        while((s[0]=c) == ' ' || c == '\t')
                c = getch();

        s[1]='\0';

        if(!isdigit(c) && c!= '.')
                return c;

        i = 0;

        if(isdigit(c))
                while(isdigit(s[++i] =c=getch()))
                        ;

        if(c=='.')
                while(isdigit(s[++i] =c=getch()))
                        ;
        s[i]='\0';

        if(c!=EOF)
                lastc=c;

        return NUMBER;
}

The program execution looks like this.

10 10 +
        20
201 305 + 20 *
        10120

Visualize It

Try It