Proofs: Dijkstra's two-stack expression evaluation
These are the human proofs of Dijkstra's two-stack expression evaluation, at full length.
The two-stack algorithm returns the value of a fully parenthesized expression full
This proof shows: correctness.
Setting. The input is a token sequence of an expression of the grammar . The value is the number for a number, and for . We write a stack as a sequence from the bottom to the top, and for with pushed. One step is one pass of the loop of lines L2 to L8 on one token.
Lemma. Let be an expression of the grammar, and suppose the loop is about to read the first token of with value stack and operator stack . Then after the loop has read all tokens of , and no others, the value stack is and the operator stack is . No step on a token of pops from an empty stack, and no step reads or changes the entries of and .
Proof. By induction on the length of .
Case is a number . is one token. Line L8 pushes , so the stacks become and , and .
Case . and are shorter than , so the induction hypothesis holds for them. The token ( is handled by line L3 and changes nothing. By the hypothesis for , started on , the stacks after are and , where , and the steps on did not touch and . The token is pushed by line L4: the stacks are and . By the hypothesis for , started on these stacks, the stacks after are and , with . The last token is ), handled by lines L6 and L7. Line L6 pops from the operator stack, then and from the value stack; none of these stacks is empty. Line L7 pushes . The stacks are and . The pops removed only the entries pushed while reading , so the entries of and were not read or changed.
Theorem. On the tokens of an expression , EVALUATE returns , and when it returns, both stacks are empty.
Proof. Line L1 makes both stacks empty. The loop reads exactly the tokens of . By the lemma with and empty, after the loop the value stack holds the single entry and the operator stack is empty. Line L9 pops and returns , which leaves the value stack empty.
Without left parentheses. Line L3 does nothing on (, so deleting every ( from the input deletes only steps that do not change the state. The other steps see the same stacks as before, so the algorithm returns the same value on the input with all ( removed.
Running time. Each token causes one step of work, and each ) causes three pops and one push. So the time is . By the lemma, the stacks during the steps on hold at most the entries of the enclosing calls plus those of ; by induction on the nesting depth of , the value stack never holds more than entries and the operator stack never more than .