Reputation: 13859
I need to disable some alternative in big list of them, for some concrete context. I decided to do this via semantic predicate, but faced strange behaviour. It looks like I'm doing smth wrong, but I can't understand why.
Below is a maximally simplified grammar, which should allow me to show whats going on;
Input text is 101
and I expect it to be parsed as (rule1 1 0 1)
. Because of failed predicate I expect antlr to chose second alternative for rule1
, which exactly match input sequence.
But Antlr throws an exception line 1:1 no viable alternative at input '0'
and produce such parse tree: (rule1 1 (rule2 0 1))
.
grammar Test;
rule1:
'1' rule2
| '1' '0' '1' // This branch should be checked, if predicate in rule2 fail and no viable alternative was found
;
rule2:
{false}? '0' '1'
| '1' '1' // this branch will not match
;
I have tried to catch exception and do smth with it, but I can understand how. I think I should somehow report parser, that this branch fails, and it should try next one.
Am I doing all wrong, or I just miss smth trivial?
P.S. Yes, it's a hack, and I'd better split my rule2
alternatives and use in rule1
only list of valid ones, but it will lead to problem's with alternative precedence and make direct left recursion - indirect in my actual grammar.
Upvotes: 2
Views: 605
Reputation: 99989
Semantic predicates in an ANTLR 4 parser rule can have two effects:
PredicateFailedException
if it returns false).The first case is only used when a predicate appears on the left side of a decision. Since your grammar includes a '1'
between the start of rule1
and when it gets to the predicate in rule2
, the predicate will not be evaluated as part of choosing between the first and second alternatives in rule1
(it will be assumed to be true). You could refactor your grammar as follows to fully preserve the original parse tree while also enabling the predicate during prediction.
grammar Test;
rule1:
'1' ( rule2
| '0' '1' // This branch should be checked, if predicate in rule2 fail and no viable alternative was found
)
;
rule2:
{false}? '0' '1'
| '1' '1' // this branch will not match
;
Upvotes: 2