Main ArticleExamples TOC

Takmela: Parsing arithmetic expression example (1+2+3, ambiguity)

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
New continuations:
expr/0expr/0 ; expr → expr• `+` expr ; expr
expr/0 → 1, expr('1')
Iteration 0
Worklist - successes
jS expr/0 → 1 expr('1')
Worklist - continuations
S⤚ expr/0expr/0 ; expr → expr• `+` expr
#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
New continuations:
expr/2expr/2 ; expr → expr• `+` expr ; expr
expr/2expr/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
Worklist - successes
jS expr/2 → 3 expr('2')
Worklist - continuations
S⤚ expr/2expr/2 ; expr → expr• `+` expr
S⤚ expr/2expr/0 ; expr → expr `+` expr•
#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
New continuations:
expr/4expr/4 ; expr → expr• `+` expr ; expr
expr/4expr/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
Worklist - successes
jS expr/4 → 5 expr('3')
jS expr/0 → 3 expr(expr('1'),'+',expr('2'))
Worklist - continuations
S⤚ expr/4expr/4 ; expr → expr• `+` expr
S⤚ expr/4expr/2 ; expr → expr `+` expr•
#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]
New continuations:
expr/4expr/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
Worklist - successes
jS expr/2 → 5 expr(expr('2'),'+',expr('3'))
Worklist - continuations
jK expr/4expr/0 ; expr → expr `+` expr•
#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
Worklist - successes
jS expr/0 → 5 expr(expr('1'),'+',expr(expr('2'),'+',expr('3')))expr(expr(expr('1'),'+',expr('2')),'+',expr('3'))
Worklist - continuations
#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
Worklist - successes
nJ Root/0 → 5 Root(expr(expr('1'),'+',expr(expr('2'),'+',expr('3'))))Root(expr(expr(expr('1'),'+',expr('2')),'+',expr('3')))
Worklist - continuations
(No new calls or successes that can be further processed)
Iteration 6 [Fixed point reached]