Operands and temporary results are always stacked as strings, and each operator is
applied by calling eval. When an error occurs inside an expression, a result operand of
ERROR is pushed, which makes all remaining operators fail in eval too. ERROR es-
sentially percolates to the top of the expression. At the end, it’s the last operand and is
displayed in the text entry field to alert you of the mistake:
5) Entered keys: "1 + 3 * ( 1 + 3 * 4 <eval>" [result = *ERROR*]
(['+', '*', '(', '+', '*'], ['1', '3', '1', '3', '4']) [on eval]
(['+', '*', '(', '+'], ['1', '3', '1', '12'])
(['+', '*', '('], ['1', '3', '13'])
(['+', '*'], ['1', '*ERROR*'])
(['+'], ['*ERROR*'])
(['+'], ['*ERROR*', '*ERROR*'])
Try tracing through these and other examples in the calculator’s code to get a feel for
the stack-based evaluation that occurs. Once you understand the general shift/reduce
(push/pop) mechanism, expression evaluation is straightforward.
PyCalc source code
Example 19-20 contains the PyCalc source module that puts these ideas to work in the
context of a GUI. It’s a single-file implementation (not counting utilities imported and
reused). Study the source for more details; as usual, there’s no substitute for interacting
with the program on your own to get a better feel for its functionality.
Also see the opening comment’s “to do” list for suggested areas for improvement. Like
all software systems, this calculator is prone to evolve over time (and in fact it has, with
each new edition of this book). Since it is written in Python, such future mutations will
be easy to apply.
Example 19-20. PP4E\Lang\Calculator\calculator.py
#!/usr/local/bin/python
"""
################################################################################
PyCalc 3.0+: a Python/tkinter calculator program and GUI component.
Evaluates expressions as they are entered, catches keyboard keys for
expression entry; 2.0 added integrated command-line popups, a recent
calculations history display popup, fonts and colors configuration,
help and about popups, preimported math/random constants, and more;
3.0+ (PP4E, version number retained):
-port to run under Python 3.X (only)
-drop 'L' keypress (the long type is now dead in earnest)
3.0 changes (PP3E):
-use 'readonly' entry state, not 'disabled', else field is greyed
out (fix for 2.3 Tkinter change);
-avoid extended display precision for floats by using str(), instead
of x
/repr() (fix for Python change);
PyCalc: A Calculator Program/Object | 1469