Skip to content

Step 1 of 3 · Reading · ~2 min

Getting Precedence Right

Parsing Expressions

Verifying Precedence End to End

With the full ladder wired up (equality → comparison → term → factor → unary → primary), this lesson is about proving it actually behaves correctly on the cases that matter, plus adding primary — the base case that includes literals, true/false/nil, and parenthesized groups.

primary: The Base Case

python

The key idea: a parenthesized expression calls back into expression() — the top of the precedence ladder — not into any single intermediate rule. That's what lets (1 + 2) * 3 work: inside the parens, the full ladder is available again, so + is legal there even though factor (which is parsing the outer * 3) wouldn't itself accept a bare +.

Associativity, Made Concrete

  • Left-associative (all your binary operators): 1 + 2 + 3(+ (+ 1.0 2.0) 3.0). Each new operator wraps the previous result on the left.
  • Verify this explicitly: if your parser instead produces (+ 1.0 (+ 2.0 3.0)), the loop is building the tree backwards — a bug that won't matter for + (associative and commutative) but will silently corrupt results for - and /, where 1 - 2 - 3 and 1 - (2 - 3) differ.

Precedence, Made Concrete

  • 1 + 2 * 3(+ 1.0 (* 2.0 3.0)) — multiplication is nested inside the addition because term's call to factor() fully consumes 2 * 3 as one indivisible operand before term's loop ever sees the +.
  • -1 + 2(+ (- 1.0) 2.0) — unary minus binds only to 1, not to the whole 1 + 2, because unary is called before term's loop starts, so it only ever sees one factor-level operand at a time.

Syntax Errors: Reporting Without Crashing

When primary() finds a token that can't start any expression — a stray ), a dangling operator, end of input where a value was expected — that's a syntax error, and it should be reported in a specific, parseable format:

[line N] Error at '<token>': Expect expression.

Rather than letting an exception crash the whole program, catch it at the statement or top level, print the message, and — in a real compiler — enter panic-mode recovery: skip tokens until you reach a likely statement boundary (like a ; or a keyword such as class/fun/var) and resume parsing from there, so one typo doesn't hide every other error in the file. For this exercise, focus on producing the exact error message and location; the discipline of "report and recover" is the same one you saw in the scanner, and you'll lean on it again when statements are introduced.

Up nextAbstract Syntax TreesParsing Expressions

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…