# JOURNAL — phase `parse` ## Approach Recursive-descent parser with standard precedence climbing: - `expr` handles `+` and `-` (lowest precedence), left-associative via iteration - `_term` handles `*` and `/` (higher precedence), left-associative via iteration - `_unary` handles unary `-` recursively (right-recursive so `--5` works) - `_primary` handles numbers and parenthesized subexpressions Empty input detected early (before `_Parser` is constructed) by checking if the token list is empty or contains only EOF. This avoids a confusing error path through `_primary`. ## Gate verification results (local) - 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: all 5 error cases raise `ParseError` ✓ - D6: 30 tests, 0 failures ✓