Reputation: 23497
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
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