# JOURNAL-parse.md ## 2026-06-15T01:21Z — Parser implementation ### Approach Implemented a classic recursive-descent parser with three precedence levels: - `_expr()`: handles `+` / `-` (lowest precedence, left-associative) - `_term()`: handles `*` / `/` (middle precedence, left-associative) - `_unary()`: handles unary `-` (right-associative by recursion) - `_primary()`: handles NUMBER literals and `(` expr `)` Left-associativity falls out naturally from the while-loop accumulation pattern in `_expr()` and `_term()`: each iteration wraps the running `node` as the left child of a new `BinOp`. Unary minus recurses into itself (`_unary()` calls `_unary()`) which gives right-associativity for `--5` → `Unary('-', Unary('-', Num(5)))`. ### Verification run ``` $ python -m unittest -q Ran 43 tests in 0.001s OK ``` Manual shape checks: ``` D1 1+2*3: BinOp('+', Num(1), BinOp('*', Num(2), Num(3))) ✓ D2 8-3-2: BinOp('-', BinOp('-', Num(8), Num(3)), Num(2)) ✓ D2 8/4/2: BinOp('/', BinOp('/', Num(8), Num(4)), Num(2)) ✓ D3 (1+2)*3: BinOp('*', BinOp('+', Num(1), Num(2)), Num(3)) ✓ D4 -5: Unary('-', Num(5)) ✓ D4 -(1+2): Unary('-', BinOp('+', Num(1), Num(2))) ✓ D4 3*-2: BinOp('*', Num(3), Unary('-', Num(2))) ✓ D5 '1 +': ParseError: unexpected end of input ✓ D5 '(1': ParseError: expected 'RPAREN' but got 'EOF' ✓ D5 '1 2': ParseError: unexpected token after expression ✓ D5 ')(': ParseError: unexpected token 'RPAREN' ✓ D5 '': ParseError: empty expression ✓ ``` ### Error handling design - Empty token list (just EOF): caught in `parse()` before entering `_expr()` - Trailing operator (`1 +`): `_primary()` sees EOF, raises ParseError - Unclosed paren (`(1`): `_consume('RPAREN')` fails with ParseError - Extra number (`1 2`): `parse()` checks `peek() != EOF` after `_expr()` returns - `)` before `(`: `_primary()` sees RPAREN, not a valid primary, raises ParseError