Skip to content
Operator Precedence & Grouping
step 1/3

Reading — step 1 of 3

Getting Precedence Right

~2 min readParsing Expressions

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:

PrecedenceOperatorsName
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…