Lesson 3: Divide and Conquer
As the custom parser system demonstrates, modular program design is almost always
a major win. By using Python’s program structuring tools (functions, modules, classes,
and so on), big tasks can be broken down into small, manageable parts that can be
coded and tested independently.
For instance, the scanner can be tested without the parser by making an instance with
an input string and calling its scan or match methods repeatedly. We can even test it
like this interactively, from Python’s command line. When we separate programs into
logical components, they become easier to understand and modify. Imagine what the
parser would look like if the scanner’s logic was embedded rather than called.
Pathologically big numbers are handled well, too, because Python’s built-in objects and
operators are used along the way:
>>> x.parse('888888888888888888888888888888888888888888888.9999999')
8.88888888889e+44
>>> x.parse('99999999999999999999999999999999999999999 + 2')
100000000000000000000000000000000000000001
>>> x.parse('999999999999999999999999999999.88888888888 + 1.1')
1e+30
In addition, there is an interactive loop interface in the testparser module if you want
to use the parser as a simple command-line calculator (or if you get tired of typing parser
method calls). Pass the Parser class, so testparser can make one of its own:
>>> import testparser
>>> testparser.interact(parser1.Parser)
<class 'parser1.Parser'>
Enter=> 4 * 3 + 5
17
Enter=> 5 + 4 * 3
17
Enter=> (5 + 4) * 3
27
Enter=> set a 99
Enter=> set b 66
Enter=> a + b
165
Enter=> # + 1
Lexical Error at column: 0
=> # + 1
=> ^
Enter=> a * b + c
'c' is undefined at column: 8
=> a * b + c
=> ^
Enter=> a * b * + c
Syntax Error at column: 8
=> a * b * + c
=> ^
Enter=> a
1448 | Chapter 19: Text and Language