Search code examples
ceof

Regarding `EOF`-related conditions in a C reverse polish calculator


I've been following the K&R C book and I'm confused with one part of the given code for the reverse polish calculator in section 4.3.

There's an if statement at the bottom of the getop function

/* 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 != '.')
        return c;    /* not a number */
    i = 0;
    if (isdigit(c))    /* collect integer part */
        while (isdigit(s[++i] = c = getch()))
            ;
    if (c == '.')    /* collect fractional part */
        while (isdigit(s[++i] = c = getch()))
            ;
    s[i] = '\0';
    if (c != EOF)
        ungetch(c);
    return NUMBER;
}

which (other than when c == EOF) puts the last character onto the getch/ungetch buffer, because it will need to be read when we get the next operator/operand.

But if we have EOF, then it is not put onto the buffer (rightly so, since the buffer only takes chars and EOF may not be a char since it it implementation-dependent whether chars are signed or unsigned), so when we go through getop the next time, when the first getch function happens it will not pick up the EOF from the previous going-through of getop. Therefore the EOF won't be returned by getop.

This seems like incorrect behaviour (by my reasoning), since the condition to keep running the calculator depends on not getting an EOF returned by getop (that is, when we reach the end of the file, we should stop running the program), but it seems that an EOF immediately after a digit character will slip through, undetected.

What am I understanding incorrectly (I expect it has something to do with how EOF works)?

I tried to think about what would happen in a concrete example, say where we have

1EOF2+\nEOF

as input to the calculator.

The expected behaviour is that 1 is printed and the calculator stops running.

My reasoning says that

  • going through the code, we get to the s[i] = '\0'; line, where we overwrite s[1] (which was EOF) with \0, so s is the string "1".
  • We get to the if(c != EOF) condition with c == EOF. We return NUMBER and 1 is successfully pushed to the stack.
  • Now we go back through getop.
  • We do the first getch function and get the next character, '2', since the getch/ungetch buffer is empty because we didn't ungetch EOF.
  • We push 2 to the stack.
  • The next time, getop returns '+', so we pop 1 and 2 and push 3.
  • We get a new line \n so we print 3.
  • We get an EOF so we stop running the calculator.

This seems like the wrong behaviour. What am I getting wrong?


Solution

  • EOF is not a character and it is not stored in the buffer. It is a state of stream or file.

    So every time you try to read the file/stream you will get EOF.

    1EOF2+\nEOF is a nonsense as EOF is not in a buffer.