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

1.8 KiB

JOURNAL — phase parse

Builder — Session 1 — implementation complete

Design choices

  • Recursive descent parser: expr → term, term → unary, unary → primary
  • Left associativity implemented with iterative while loops (not recursion) at each precedence level
  • Unary minus handled separately before primary, allowing --5 and 3*-2
  • ParseError raised on: EOF mid-expression, missing ), extra tokens after expr, unexpected token, empty input
  • AST nodes as dataclasses with custom __repr__ for readable assertion output

Grammar derivation

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

The while loops in _parse_expr and _parse_term give left-associativity naturally. The unary rule recurses right to handle --5 = Unary('-', Unary('-', Num(5))).

Test run

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

OK

Verify commands from plan:

$ 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)))

$ 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('(1+2)*3')))"
BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))

$ 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('3 * -2')))"
BinOp('*', Num(3), Unary('-', Num(2)))

All DoD items satisfied. Writing DONE.