One Two Three
One Two Three

Reputation: 23497

specifying a grammar rule of "appearing in any order but only at most once"

Say I have three symbols A, B, C.

In ANTLR, how do I specify that in a sentence, A, B, and C can appear at most once and that they can occur in any order. (For eg., ABC, BCA are both legit)

I tried

(A | B | C)*

knowing it'd only take care of the "any order" part, but couldn't think of a way to say it can only appear at most once.

Edited: I've tried using boolean flags, which worked but seems too hairy - there has to be a simpler way, yes?

myrule;
   {
       boolean aSeen = false;
       boolean bSeen = false;
       boolean cSeen = false;
   }
   :

   (   A { if (aSeen) throw RuntimeException("alraedy seen") else aSeen = true; }
   |   B { if (bSeen) throw RuntimeException("alraedy seen") else bSeen = true; }
   |   C { if (cSeen) throw RuntimeException("alraedy seen") else cSeen = true; }
   )*
   ;

Upvotes: 4

Views: 576

Answers (1)

TomServo
TomServo

Reputation: 7409

Since you mention there could be many, many permutations, I would instead opt to keep the grammar dead simple and handle this in the visitor or listener, for example:

public class ValuesListener : ValuesBaseListener
{
    bool isASeen = false;  // "seen flag here"  

    public override void ExitA(ValuesParser.AContext context)
    {
        if (isASeen) // already parsed this once
            <throw exception to stop and inform user>
        else // first time parsing this, so process and set flag so it won't happen again
        {
            isASeen = true;  // never gets reset during this tree walk
            <perform normal processing here>
        }
    }
}

Then your grammar can be something like

myrule: someothertoken myRuleOptions* ;

myRuleOptions
:    A
|    B
|    C
| ...etc. 

My reason? There are ways to do it with predicates as suggested above, but for readability and maintainability by engineers inexperienced in ANTLR4 but very experienced in the target language, I would consider this approach. In my environment, I often hand off ANTLR projects to engineers who simply follow a pattern that I establish, and who don't really understand ANTLR. This is easier for them to follow.

Upvotes: 2

Related Questions