Skip to content

Evaluating postfix

A postfix expression is worked out in one pass: push the numbers, and let each operator pop two and push their result. No brackets, no precedence.

Helps to know firstInfix to postfix

Helps to know first
This topic

First, the picture

8 2 - 3 * 4 + has no brackets and no precedence, yet it has one answer. Watch a stack work it out.

Calculating with a stack

Numbers wait on the stack; each operator takes two and gives one back

bool eval_postfix(const char *s, int *result){    int stack[MAX];    int top = 0;    for (size_t i = 0; s[i] != '\0'; i++) {        char c = s[i];        if (c == ' ')            continue;        if (c >= '0' && c <= '9') {            if (top == MAX)                return false;            stack[top] = c - '0';            top++;            continue;        }        if (top < 2)            return false;        top--;        int b = stack[top];        top--;        int a = stack[top];        int r;        if (c == '+')            r = a + b;        else if (c == '-')            r = a - b;        else if (c == '*')            r = a * b;        else if (c == '/' && b != 0)            r = a / b;        else            return false;        stack[top] = r;        top++;    }    if (top != 1)        return false;    *result = stack[0];    return true;}int main(void){    const char *exprs[4] = { "8 2 - 3 * 4 +", "8 2 3 * - 4 +", "8 +", "8 2" };    for (int i = 0; i < 4; i++) {        int v;        if (eval_postfix(exprs[i], &v))            printf("%-14s= %d\n", exprs[i], v);        else            printf("%-14serror\n", exprs[i]);    }    return 0;}

i is 0: evaluate "8 2 - 3 * 4 +".

Output

0.00 / 11.00 s
Describe this picture

Lines 6 to 45 (eval_postfix) and 47 to 58 (main) of eval.c, with the line about to run marked. Beside the code is a picture in two parts. At the top, labelled S, is the string as a row of character boxes, with narrow gaps for the spaces and the operators tinted. The character being read has a ring around it; those already read are dimmed. Below, labelled STACK, is eval_postfix’s int array stack standing upright, stack[0] at the bottom, cells 0 to 3 drawn and a dashed stub for the other twenty-eight. top is a bold line across it at the boundary above the last value, labelled “top” and its value; cells at or above top are dimmed but keep their numbers. The clip plays once, about 11 seconds. 8 and then 2 land on the stack. At -, the two cells are ringed and three lines appear beside the stack: “b = 2, the top”, “a = 8, under it” and “a - b = 8 - 2 = 6”; then 6 lands in stack[0], where the 8 was. 3 lands; * lifts 6 and 3 and writes “a * b = 6 * 3 = 18”; 18 lands. 4 lands; + lifts 18 and 4 and writes “a + b = 18 + 4 = 22”; 22 lands, alone on the stack. It is written to main’s v, the words “v = 22” appear, and the clip rests on the output 8 2 - 3 * 4 + = 22. Under the picture are one sentence on the current step and the output. The transport plays and pauses, steps one beat back or forward, and scrubs; a paused step is kept in the page address as calc.step.

Numbers wait, operators work

Infix to postfix turned (8 - 2) * 3 + 4 into 8 2 - 3 * 4 +. Working that out needs one stack and one rule for each kind of token:

  • A number is pushed.
  • An operator pops two values, works on them, and pushes the result.
  • At the end, exactly one value is left: the answer.

There is no precedence to look up and no bracket to match. The rewriting into postfix has already put every operator just after the two values it works on, so the order of the tokens says it all.

The code and its cost

The function

bool eval_postfix(const char *s, int *result)
{
    int stack[MAX];
    int top = 0;
    for (size_t i = 0; s[i] != '\0'; i++) {
        char c = s[i];
        if (c == ' ')
            continue;
        if (c >= '0' && c <= '9') {
            if (top == MAX)
                return false;
            stack[top] = c - '0';
            top++;
            continue;
        }
        if (top < 2)
            return false;
        top--;
        int b = stack[top];
        top--;
        int a = stack[top];
        int r;
        if (c == '+')
            r = a + b;
        else if (c == '-')
            r = a - b;
        else if (c == '*')
            r = a * b;
        else if (c == '/' && b != 0)
            r = a / b;
        else
            return false;
        stack[top] = r;
        top++;
    }
    if (top != 1)
        return false;
    *result = stack[0];
    return true;
}

The stack is an array of 32 ints with top counting the values, as in Stacks. c - '0' turns the character '8' into the number 8, because the digit characters are consecutive. The answer goes back through the pointer result; the function itself returns whether the string made sense.

Which value is on the left

The first value popped is b, the right operand, because it was pushed last. The second is a, the left one. For 8 2 - that gives 8 − 2 = 6. Pop them the other way round and - gives −6, and / goes wrong in the same way; + and * would hide the mistake, since their order does not matter.

Errors

StringWhat goes wrongLine
8 ++ finds only one value22
8 2the end leaves two values, not one42
8 0 /division by zero37

The program in the clip checks four strings. The first two are worked out, the last two are errors:

8 2 - 3 * 4 + = 22
8 2 3 * - 4 + = 6
8 +           error
8 2           error

What it costs

Each character is read once, and each token costs a fixed few steps: a push, or two pops and a push. A string of n characters takes about n steps (O(n) in the notation of lesson 3.3). Joined to 8.3’s function, an infix expression goes in and its value comes out after two passes.

Running it yourself

gcc -std=c11 -Wall -Wextra -pedantic eval.c -o eval
./eval

Worked example

4 1 3 + 2 * + 5 -. The stack after each token:

Token413+2*+5-
Stack44 14 1 34 44 4 24 81212 57

The answer is 7, and the stack is never more than three deep.

Order matters. 9 3 / is 9 / 3 = 3. 3 9 / is 3 / 9, which is 0 in integer division.

Back to infix. 8.3’s second output, 8 2 3 * - 4 +, is 2 × 3 = 6, then 8 − 6 = 2, then 2 + 4 = 6: the value of 8 - 2 * 3 + 4.

Questions. 5 2 - 4 * is (5 − 2) × 4 = 12. 8 + is an error because + has too few operands; 8 2 is an error of the other kind, a value left over.

Where it’s used

Calculators. Some calculators take their input in postfix, called reverse Polish entry: you key in 8, 2, then -, and the display shows the stack.

Virtual machines. Many languages compile programs into instructions for a stack machine, where push 8, push 2, subtract works exactly as here.

Page languages. PostScript, the printer language, and the drawing instructions inside PDF files are written in postfix and run on a stack.

What comes next. Working out an expression tree in postorder (12.3) is this same evaluation, with the tree in place of the string.

Reference card

Code or ideaMeaning
numberpush it
operatorpop b, then a; push a op b
c - '0'the digit’s value
endexactly one value: the answer
top < 2 at an operator / top != 1 at the endtoo few operands / values left over
costone pass, about n steps (O(n), lesson 3.3)

Platform: C11, gcc on x86-64 Linux: char 1 byte, int 4, little-endian. Division of ints rounds toward zero.

End of the lesson

Where to go next.

New lessons by email

Are you 13 or over?

Accounts and email updates are for people aged 13 or over. We keep only your answer, never your date of birth.

Phasorium

Account

Sign inWith Google, GitHub or your email

Subjects

Site

Look