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

1.6 KiB

JOURNAL-parse — Builder

2026-06-15

Implementation

Built calc/parser.py as a classic recursive-descent parser with three precedence levels:

expr   → term   (('+' | '-') term)*       # left-assoc, lowest
term   → unary  (('*' | '/') unary)*      # left-assoc, higher
unary  → '-' unary | primary              # right-recursive for nested --
primary→ NUMBER | '(' expr ')'

This naturally yields left-associativity (the while loop builds left-leaning trees) and correct precedence (mul/div are parsed inside term which is called from expr).

Test run output

$ python -m unittest -q
......................................................
Ran 46 tests in 0.001s

OK

(46 = 9 existing lex tests + 17 new parser tests)

Manual gate verification

D1 add-mul: BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))   ✓
D1 mul-add: BinOp('+', BinOp('*', Num(2), Num(3)), Num(1))   ✓
D2 sub:     BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))    ✓
D2 div:     BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))    ✓
D3 paren:   BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))   ✓
D4 unary:   Unary('-', Num(5))                                 ✓
D4 u-paren: Unary('-', BinOp('+', Num(1), Num(2)))            ✓
D4 mul-u:   BinOp('*', Num(3), Unary('-', Num(2)))            ✓
D5 '1 +'  → ParseError: unexpected token 'EOF' (None)         ✓
D5 '(1'   → ParseError: expected RPAREN, got 'EOF' (None)     ✓
D5 '1 2'  → ParseError: unexpected token 'NUMBER' (2) after expression  ✓
D5 ')('   → ParseError: unexpected token 'RPAREN' (')')        ✓
D5 ''     → ParseError: empty expression                       ✓