- onto operators, and continue scanning user inputs. When “eval” is pressed at the end,
4 is pushed onto operands, and the final + on operators is applied to stacked operands.
The text input and display field at the top of the GUI’s main window plays a part in
this algorithm, too. The text input field and expression stacks are integrated by the
calculator class. In general, the text input field always holds the prior operand when
an operator button is pressed (e.g., on 5 *); the text in the input field is pushed onto
the operands stack before the operator is resolved. Because of this, we have to pop
results before displaying them after “eval” or ) is pressed; otherwise the results are
pushed onto the stack twice—they would be both on the stack and in the display field,
from which they would be immediately pushed again when the next operator is input.
For both usability and accuracy, when an operator is seen, we also have to arrange to
erase the input field’s prior value when the next operand’s entry is started (e.g., on both
3 and 4 in 5 3 + 4). This erasure of the prior values is also arranged when “eval”
or ) is applied, on the assumption that a subsequent operand key or button replaces
the prior result—for a new expression after “eval,” and for an operand following a new
operator after ); e.g., to erase the parenthesized 12 result on 2 in 5 + (3 4) * 2.
Without this erasure, operand buttons and keys simply concatenate to the currently
displayed value. This model also allows user to change temporary result operands after
a ) by entry of operand instead of operator.
Expression stacks also defer operations of lower precedence as the input is scanned. In
the next trace, the pending + isn’t evaluated when the button is pressed: since binds
tighter, we need to postpone the + until the can be evaluated. The operator isn’t
popped until its right operand 4 has been seen. There are two operators to pop and
apply to operand stack entries on the “eval” press—the at the top of operators is
applied to the 3 and 4 at the top of operands, and then + is run on 5 and the 12 pushed
for :
2) Entered keys: "5 + 3 * 4 <eval>" [result = 17]
(['+', '*'], ['5', '3', '4']) [on 'eval' press]
(['+'], ['5', '12']) [displays "17"]
For strings of same-precedence operators such as the following, we pop and evaluate
immediately as we scan left to right, instead of postponing evaluation. This results in
a left-associative evaluation, in the absence of parentheses: 5+3+4 is evaluated as
((5+3)+4). For + and * operations this is irrelevant because order doesn’t matter:
3) Entered keys: "5 + 3 + 4 <eval>" [result = 12]
(['+'], ['5', '3']) [on the second '+']
(['+'], ['8', '4']) [on 'eval']
The following trace is more complex. In this case, all the operators and operands are
stacked (postponed) until we press the ) button at the end. To make parentheses work,
( is given a higher precedence than any operator and is pushed onto the operators stack
to seal off lower stack reductions until the ) is seen. When the ) button is pressed, the
PyCalc: A Calculator Program/Object | 1467