Abhishek Tiwari
Abhishek Tiwari

Reputation: 332

Unable to write Antlr3 rule for situation

I have a special case where I am not able to write Antlr3 parser rule for that.

I have 5 parser rules, let say: a,b,c,d and e.

Conditions:

  1. They can be in any order.
  2. Every rule is optional.
  3. Each rule can only be once in syntax.
  4. In syntax there would either be 'a' or 'b'. Both can not be in syntax.

Possible cases:

Is Antlr provide any easy way to implement this? It is possible by implementing rule for each combination of rule.

Upvotes: 0

Views: 76

Answers (2)

sprinter
sprinter

Reputation: 27966

A possible way to do this would be with context-dependent predicates. How you would implement would be language dependent but it might look something like:

statement : element*;

element : {!seen(a) && !seen(b)}? a {add(a);}
    | {!seen(a) && !seen(b)}? b {add(b);}
    | {!seen(c) c {add(c);}
    ....

Essentially this stops the parser considering an option after it's been seen once.

Here is a very simple example using Java:

@parser::header {
    import java.util.EnumSet;
    import java.util.List;
}
@parser::members {
    public enum Val {A, B, C, D, E};
    public EnumSet<Val> result = EnumSet.noneOf(Val.class); 
}

statement : (a|b|c|d|e)+ EOF;

a : {!result.contains(Val.A) && !result.contains(Val.B)}? 'a' {result.add(Val.A);};
b : {!result.contains(Val.A) && !result.contains(Val.B)}? 'b' {result.add(Val.B);};
c : {!result.contains(Val.C)}? 'c' {result.add(Val.C);};
d : {!result.contains(Val.D)}? 'd' {result.add(Val.D);};
e : {!result.contains(Val.E)}? 'e' {result.add(Val.E);};

Upvotes: 3

Mike Lischke
Mike Lischke

Reputation: 53337

ANTLR4 doesn't allow to implement all those conditions you specified. Especially the condition that rules may appear in any order but only once is something that is barely supported by any parser.

However, you can use a two step approach. First, allow all rules to appear in any order. Done usually like this:

main: sub*;
sub: a | b | c;

After parsing you can do another step (usually you will have a semantic step anyway, which would qualify here too) and check the occurences in the generated parse tree. You can then throw a detailed error message telling the user what is not allowed (which is tricky, if not impossible, if you try to do that in parser rules). The approach laid out by @sprinter is ok too, but it will not give you any meaningful error message, but just tell you that rule element had no viable alt (which can have many reasons, not only duplicate rules).

And with that second step you can easily apply any additional condition (specific orders, rules that must not go together etc., without having to change your grammar), which you cannot do in the parsing step (since you cannot lookahead rules).

Upvotes: 3

Related Questions