Reading — step 1 of 3
Getting Precedence Right
Operator Precedence & Grouping
Operator precedence determines which operations bind more tightly. Without it, 1 + 2 * 3 would be ambiguous — is it (1 + 2) * 3 = 9 or 1 + (2 * 3) = 7? By convention (and mathematics), multiplication binds tighter, so the answer is 7.
Precedence Levels
From lowest to highest precedence in our language:
| Precedence | Operators | Name |
|---|---|---|
| 1 (lowest) | == != | Equality |
| 2 | < <= > >= | Comparison |
| 3 | + - | Term (addition) |
| 4 | * / | Factor (multiplication) |
| 5 (highest) | ! - (unary) | Unary |
In the grammar, lower precedence means higher in the rule hierarchy:
expression → equality
equality → comparison ( ("==" | "!=") comparison )*
comparison → term ( ("<" | "<=" | ">" | ">=") term )*
term → factor ( ("+" | "-") factor )*
factor → unary ( ("*" | "/") unary )*
unary → ("!" | "-") unary | primary
Each rule only matches operators at its level, then delegates to the next-higher-precedence rule for operands. This structural encoding of precedence is elegant — no precedence tables needed.
Left-to-Right Associativity
1 + 2 + 3 should parse as (1 + 2) + 3, not 1 + (2 + 3). This is left-associative. The while loop in each grammar rule naturally produces left-associative trees:
left = factor()
while match(PLUS, MINUS):
right = factor()
left = Binary(left, op, right) // left becomes the new node
Grouping with Parentheses
Parentheses override precedence: (1 + 2) * 3 forces addition first. In the grammar, parentheses appear at the primary level:
primary → NUMBER | STRING | "true" | "false" | "nil"
| "(" expression ")"
When we encounter (, we recursively call expression() — which starts back at the lowest precedence. This is how parentheses "reset" precedence.
How Python Handles Precedence
Python defines 18 precedence levels (from assignment at the bottom to await at the top). CPython's parser uses a PEG (Parsing Expression Grammar) parser generator since Python 3.9, replacing the older LL(1) parser. But the fundamental idea is identical to what we are building.
Your Task
Verify that your parser handles all precedence levels correctly, including grouping with parentheses and left-to-right associativity.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…