Seagull
Seagull

Reputation: 13859

Antlr4 failed semantic predicate should lead to picking another alternative

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

Answers (1)

Sam Harwell
Sam Harwell

Reputation: 99989

Semantic predicates in an ANTLR 4 parser rule can have two effects:

  1. The predicate could be evaluated as part of the prediction process, which determines the path taken through the grammar.
  2. The predicate could be evaluated after a decision is made as part of verifying a correct path was taken (and throwing a 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

Related Questions