The classic example in compiler books to show ambiguity, with the input being parsable as (1+2)+3 or 1+(2+3). How will Takmela parse it?
Grammar
expr : expr '+' expr
| NUM ;
NUM: [0-9]+;
WS skip: [ \r\n\t]*;
Input
1+2+3
Trace appears confusing? This might help
| Call start nonterminal | |||
![]() |
#0: Called expr/0 at the top level (will process)
Processing expr/0 codePos expr → • expr `+` expr inputPos 0
Calling: expr/0 with Cont expr/0 ; expr → expr• `+` expr ; expr [already processed]
Processing expr/0 codePos expr → • NUM inputPos 0
Match NUM to 1, matched; inputPos now 1
Reached end of rule, success! expr/0 → 1
expr/0 → expr/0 ; expr → expr• `+` expr ; expr
|
||
expr/0 → 1, expr('1')
| |||
| Iteration 0 | |||
| |||
![]() |
#1: JoinS: expr/0 → 1 木expr('1') will resume cont: expr/0 ; expr → expr• `+` expr ; expr
Processing expr/0 codePos expr → expr• `+` expr inputPos 1
Match + to +, matched; inputPos now 2
Calling: expr/2 with Cont expr/0 ; expr → expr `+` expr• ; expr(expr('1'), '+') [will process]
Processing expr/2 codePos expr → • expr `+` expr inputPos 2
Calling: expr/2 with Cont expr/2 ; expr → expr• `+` expr ; expr [already processed]
Processing expr/2 codePos expr → • NUM inputPos 2
Match NUM to 2, matched; inputPos now 3
Reached end of rule, success! expr/2 → 3
expr/2 → expr/2 ; expr → expr• `+` expr ; expr
expr/2 → expr/0 ; expr → expr `+` expr• ; expr(expr('1'), '+')
|
||
expr/0 → 1, expr('1')
expr/2 → 3, expr('2')
| |||
![]() |
#2: JoinS: expr/0 → 1 木expr('1') will resume cont: Root/0 ; Root → expr• ; Root
×Didn't reach end of input, not a successful parse
expr/0 → 1, expr('1')
expr/2 → 3, expr('2')
| ||
| Iteration 1 | |||
| |||
![]() |
#3: JoinS: expr/2 → 3 木expr('2') will resume cont: expr/2 ; expr → expr• `+` expr ; expr
Processing expr/2 codePos expr → expr• `+` expr inputPos 3
Match + to +, matched; inputPos now 4
Calling: expr/4 with Cont expr/2 ; expr → expr `+` expr• ; expr(expr('2'), '+') [will process]
Processing expr/4 codePos expr → • expr `+` expr inputPos 4
Calling: expr/4 with Cont expr/4 ; expr → expr• `+` expr ; expr [already processed]
Processing expr/4 codePos expr → • NUM inputPos 4
Match NUM to 3, matched; inputPos now 5
Reached end of rule, success! expr/4 → 5
expr/4 → expr/4 ; expr → expr• `+` expr ; expr
expr/4 → expr/2 ; expr → expr `+` expr• ; expr(expr('2'), '+')
|
||
expr/0 → 1, expr('1')
expr/2 → 3, expr('2')
expr/4 → 5, expr('3')
| |||
![]() |
#4: JoinS: expr/2 → 3 木expr('2') will resume cont: expr/0 ; expr → expr `+` expr• ; expr(expr('1'), '+')
Processing expr/0 codePos expr → expr `+` expr• inputPos 3
Reached end of rule, success! expr/0 → 3
|
||
expr/0 → 1, expr('1')
expr/2 → 3, expr('2')
expr/4 → 5, expr('3')
expr/0 → 3, expr(expr('1'),'+',expr('2'))
| |||
| Iteration 2 | |||
| |||
![]() |
#5: JoinS: expr/4 → 5 木expr('3') will resume cont: expr/4 ; expr → expr• `+` expr ; expr
Processing expr/4 codePos expr → expr• `+` expr inputPos 5
Match `+` to (eof), fail
|
||
expr/0 → 1, expr('1')
expr/2 → 3, expr('2')
expr/4 → 5, expr('3')
expr/0 → 3, expr(expr('1'),'+',expr('2'))
| |||
![]() |
#6: JoinS: expr/4 → 5 木expr('3') will resume cont: expr/2 ; expr → expr `+` expr• ; expr(expr('2'), '+')
Processing expr/2 codePos expr → expr `+` expr• inputPos 5
Reached end of rule, success! expr/2 → 5
|
||
expr/0 → 1, expr('1')
expr/2 → 3, expr('2')
expr/4 → 5, expr('3')
expr/0 → 3, expr(expr('1'),'+',expr('2'))
expr/2 → 5, expr(expr('2'),'+',expr('3'))
| |||
![]() |
#7: JoinS: expr/0 → 3 木expr(expr('1'),'+',expr('2')) will resume cont: expr/0 ; expr → expr• `+` expr ; expr
Processing expr/0 codePos expr → expr• `+` expr inputPos 3
Match + to +, matched; inputPos now 4
Calling: expr/4 with Cont expr/0 ; expr → expr `+` expr• ; expr(expr(expr('1'), '+', expr('2')), '+') [already processed]
expr/4 → expr/0 ; expr → expr `+` expr• ; expr(expr(expr('1'), '+', expr('2')), '+')
|
||
expr/0 → 1, expr('1')
expr/2 → 3, expr('2')
expr/4 → 5, expr('3')
expr/0 → 3, expr(expr('1'),'+',expr('2'))
expr/2 → 5, expr(expr('2'),'+',expr('3'))
| |||
![]() |
#8: JoinS: expr/0 → 3 木expr(expr('1'),'+',expr('2')) will resume cont: Root/0 ; Root → expr• ; Root
×Didn't reach end of input, not a successful parse
expr/0 → 1, expr('1')
expr/2 → 3, expr('2')
expr/4 → 5, expr('3')
expr/0 → 3, expr(expr('1'),'+',expr('2'))
expr/2 → 5, expr(expr('2'),'+',expr('3'))
| ||
| Iteration 3 | |||
| |||
![]() |
#9: JoinS: expr/2 → 5 木expr(expr('2'),'+',expr('3')) will resume cont: expr/2 ; expr → expr• `+` expr ; expr
Processing expr/2 codePos expr → expr• `+` expr inputPos 5
Match `+` to (eof), fail
|
||
expr/0 → 1, expr('1')
expr/2 → 3, expr('2')
expr/4 → 5, expr('3')
expr/0 → 3, expr(expr('1'),'+',expr('2'))
expr/2 → 5, expr(expr('2'),'+',expr('3'))
| |||
![]() |
#10: JoinS: expr/2 → 5 木expr(expr('2'),'+',expr('3')) will resume cont: expr/0 ; expr → expr `+` expr• ; expr(expr('1'), '+')
Processing expr/0 codePos expr → expr `+` expr• inputPos 5
Reached end of rule, success! expr/0 → 5
|
||
expr/0 → 1, expr('1')
expr/2 → 3, expr('2')
expr/4 → 5, expr('3')
expr/0 → 3, expr(expr('1'),'+',expr('2'))
expr/2 → 5, expr(expr('2'),'+',expr('3'))
expr/0 → 5, expr(expr('1'),'+',expr(expr('2'),'+',expr('3')))
| |||
![]() |
#11: JoinK: expr/4 will use expr/4 → 5 木expr('3') to resume expr/0 ; expr → expr `+` expr• ; expr(expr(expr('1'), '+', expr('2')), '+')
Processing expr/0 codePos expr → expr `+` expr• inputPos 5
Reached end of rule, success! expr/0 → 5
|
||
expr/0 → 1, expr('1')
expr/2 → 3, expr('2')
expr/4 → 5, expr('3')
expr/0 → 3, expr(expr('1'),'+',expr('2'))
expr/2 → 5, expr(expr('2'),'+',expr('3'))
expr/0 → 5, expr(expr('1'),'+',expr(expr('2'),'+',expr('3')))
expr/0 → 5, expr(expr(expr('1'),'+',expr('2')),'+',expr('3'))
| |||
| Iteration 4 | |||
| |||
![]() |
#12: JoinS: expr/0 → 5 木expr(expr('1'),'+',expr(expr('2'),'+',expr('3')))木expr(expr(expr('1'),'+',expr('2')),'+',expr('3')) will resume cont: expr/0 ; expr → expr• `+` expr ; expr
Processing expr/0 codePos expr → expr• `+` expr inputPos 5
Match `+` to (eof), fail
Processing expr/0 codePos expr → expr• `+` expr inputPos 5
Match `+` to (eof), fail
|
||
expr/0 → 1, expr('1')
expr/2 → 3, expr('2')
expr/4 → 5, expr('3')
expr/0 → 3, expr(expr('1'),'+',expr('2'))
expr/2 → 5, expr(expr('2'),'+',expr('3'))
expr/0 → 5, expr(expr('1'),'+',expr(expr('2'),'+',expr('3')))
expr/0 → 5, expr(expr(expr('1'),'+',expr('2')),'+',expr('3'))
| |||
![]() |
#13: JoinS: expr/0 → 5 木expr(expr('1'),'+',expr(expr('2'),'+',expr('3')))木expr(expr(expr('1'),'+',expr('2')),'+',expr('3')) will resume cont: Root/0 ; Root → expr• ; Root
✓Reached end of input, successful parse!
expr/0 → 1, expr('1')
expr/2 → 3, expr('2')
expr/4 → 5, expr('3')
expr/0 → 3, expr(expr('1'),'+',expr('2'))
expr/2 → 5, expr(expr('2'),'+',expr('3'))
expr/0 → 5, expr(expr('1'),'+',expr(expr('2'),'+',expr('3')))
expr/0 → 5, expr(expr(expr('1'),'+',expr('2')),'+',expr('3'))
Root/0 → 5, Root(expr(expr('1'),'+',expr(expr('2'),'+',expr('3'))))✓
Root/0 → 5, Root(expr(expr(expr('1'),'+',expr('2')),'+',expr('3')))✓
| ||
| Iteration 5 | |||
| |||
| (No new calls or successes that can be further processed) | |||
| Iteration 6 [Fixed point reached] | |||