1.6 KiB
1.6 KiB
JOURNAL — phase parse
2026-06-15
Implementation approach
Built a standard recursive-descent parser with two levels of precedence:
expr : term (('+' | '-') term)* # low precedence, left-assoc
term : factor (('*' | '/') factor)* # high precedence, left-assoc
factor : NUMBER
| '-' factor # unary minus (right-recursive)
| '(' expr ')'
The left-associativity is inherent in the while loop pattern: each
iteration wraps the current left in a new BinOp, so 8-3-2 naturally
produces BinOp('-', BinOp('-', Num(8), Num(3)), Num(2)).
Unary minus in factor uses right-recursion so --5 gives
Unary('-', Unary('-', Num(5))) and 3 * -2 gives
BinOp('*', Num(3), Unary('-', Num(2))) — the unary binds only to
what follows it, not to the whole expression.
Verification commands run
$ python -m unittest -q
Ran 50 tests in 0.001s
OK
$ 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; parse(tokenize('1 +'))"
# ParseError: unexpected token 'EOF' (None) [raised, not crash]
All five mandatory error cases (1 +, (1, 1 2, )(, "") raise
ParseError — not IndexError, KeyError, or any other exception.
Gate timeline
- feat commit
c78a0d7— parser + tests + STATUS - D1 claimed
49beb26, pushed - D2 claimed
73f747d, pushed - D3 claimed
3c97bfc, pushed - D4 claimed
686695b, pushed - D5 claimed
66d75f1, pushed - D6 claimed
272fbac, pushed - Awaiting Adversary verdict