I have an ambiguous grammar
chain
: chainBase memberAccess* ('?' | '!' | '.' Yield)?
;
memberAccess
: '&'? '.' (identifier | keyword) ('?' | '!' | '=')? functionCallInsideMember? squareExpression*?
;
which can recognize
as either chain or anotherRule. But I want chain only match "a(b).", because there is no dot after last parenthesis. What I assume can do is
1) Make a twin of memberAccess which is not matching a dot, if we consumed it inside of functionCallInsideMember(which returns a boolean value like isDotMatched). In that case I would like to make one rule from them looks like
chain
locals [boolean isDotMatched]
@init {
$isDotMatched = false;
}
: chainBase {$isDotMatched = $chainBase.matchedDot;} ( memberAccess[!$isDotMatched] {$isDotMatched = $memberAccess.matchedDot;} )* ('?' | '!' | '.' Yield)?
;
memberAccess[boolean matchDot] returns [boolean matchedDot]
@init {
$matchedDot = false;
}
: '&'? optionalDot[$matchDot] (identifier | keyword) ('?' | '!' | '=')? (functionCallInsideMember {$matchedDot = true;})? squareExpression*?
;
optionalDot[boolean matchDot]
: {$matchDot}? '.' | {!$matchDot}?;
But then antlr's "adaptivePredict" matches empty optionalDot anyway, then checking predicate and if it fails, antlr reports a NoViableAltException.I know I can catch it, but how to fail a rule matching properly then? I tried "_errHandler.recover" but it just makes antlr match incorrect input like "p a.b(0)" as my "chain" rule, which would be matched later on a some lower precedence rule.
2) Make a predicate inside of functionCallInsideMember looks like
functionCallInsideMember
: {getCurrentToken().getType() == OpenRoundBracket && getTokenAfterMatchingParen(getCurrentToken()) == Dot}?
'(' actualArguments? CloseRoundBracket ;
but antlr can't handle token references. I don't know why though, because by parse time lexer already gave us all the tokens(not really I guess, but we can assume that because antlr's philosophy is to separate lexer and parser). Why is antlr at the prediction time not shifting current tokenStream? And how can I overcome it?3) Make custom tokens which store information about next token after matching parenthesis if token is a paren itself. It would just require an array of opened parenthesis token references I guess, but it seems unnecessary for such a simple task.
P.S. Sorry for my English, and possibly for question formatting as I didn't figure out how to preview my topic here