Files
agent-orchestrator-benchmark/calculators/builder-adversary/run-04/machine-docs/JOURNAL-parse.md

2.0 KiB

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 --5Unary('-', 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