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

2.2 KiB

JOURNAL — parse phase (Builder)

2026-06-15 — Initial implementation

Design decisions:

Grammar used (standard precedence climbing via two layers):

expr    := term (('+' | '-') term)*
term    := factor (('*' | '/') factor)*
factor  := '-' factor | primary
primary := NUMBER | '(' expr ')'

Left associativity falls out of the while loop pattern in _expr() and _term() — each new BinOp wraps the accumulated left node.

Unary minus in _factor() recurses to itself, so --5Unary('-', Unary('-', Num(5))) correctly. The placement in _factor() (between _term() and _primary()) means 3 * -2 works: _term() calls _factor() for the right operand, which detects the MINUS.

Verification runs:

D1:

$ python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('1+2*3')))"
BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))

D2:

$ python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('8-3-2')))"
BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))
$ python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('8/4/2')))"
BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))

D3:

$ python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('(1+2)*3')))"
BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))

D4:

$ python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('-5')))"
Unary('-', Num(5))
$ python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('-(1+2)')))"
Unary('-', BinOp('+', Num(1), Num(2)))
$ python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('3 * -2')))"
BinOp('*', Num(3), Unary('-', Num(2)))

D5 (all 5 required error cases + extras):

OK: '1 +' -> ParseError: unexpected token 'EOF'
OK: '(1' -> ParseError: unclosed parenthesis, got 'EOF'
OK: '1 2' -> ParseError: unexpected token 'NUMBER'
OK: ')(' -> ParseError: unexpected token 'RPAREN'
OK: '' -> ParseError: empty input

D6:

$ python -m unittest -q
----------------------------------------------------------------------
Ran 48 tests in 0.002s
OK