Antlr 指定语法规则为;以任何顺序出现,但最多出现一次”;

Antlr 指定语法规则为;以任何顺序出现,但最多出现一次”;,antlr,context-free-grammar,Antlr,Context Free Grammar,假设我有三个符号A,B,C 在ANTLR中,我如何指定在一个句子中,a、B和C最多只能出现一次,并且它们可以以任何顺序出现。(例如,ABC、BCA都是合法的) 我试过了 (A | B | C)* 知道它只能处理“任意订单”部分,但想不出一种方式来表示它最多只能出现一次 编辑:我尝试过使用布尔标志,这很有效,但似乎太复杂了-必须有一个更简单的方法,是吗 myrule; { boolean aSeen = false; boolean bSeen = false;

假设我有三个符号A,B,C

在ANTLR中,我如何指定在一个句子中,a、B和C最多只能出现一次,并且它们可以以任何顺序出现。(例如,ABC、BCA都是合法的)

我试过了

(A | B | C)*

知道它只能处理“任意订单”部分,但想不出一种方式来表示它最多只能出现一次

编辑:我尝试过使用布尔标志,这很有效,但似乎太复杂了-必须有一个更简单的方法,是吗

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; }
   )*
   ;

既然你提到可能有很多很多排列,我会选择保持语法非常简单,并在访问者或听众中处理,例如:

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>
        }
    }
}

我的理由?有一些方法可以用上面提到的谓词来完成,但是对于那些在ANTLR4中没有经验但是在目标语言中很有经验的工程师来说,可读性和可维护性,我会考虑这种方法。在我的环境中,我经常将ANTLR项目交给工程师,他们只是遵循我建立的模式,并不真正理解ANTLR。这对他们来说更容易理解。

您是否考虑过简单地列出所有六种排列<代码>S:=ABC | ACB | BAC | BCA | CAB | CBA并不迷人,但概念上很简单。如果ANTLR可以使用不受限制的语法,那么您可以执行类似于
S:=ABC
AB:=BA
AC:=CA
BC:=CB
,然后向后执行最后三个操作。第一种方法需要
n制作,第二个
n^2
。不,因为这和我目前的方法一样毛茸茸的(另外,为了简化起见,我在这里只列出了3。实际上,它有5个,可能更多)可能是重复的
myrule: someothertoken myRuleOptions* ;

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