指定语法规则"以任何顺序出现,但最多只出现一次"

时间:2017-07-20 17:42:44

标签: antlr context-free-grammar

说我有三个符号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; }
   )*
   ;

1 个答案:

答案 0 :(得分:2)

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

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

然后你的语法就像

myrule: someothertoken myRuleOptions* ;

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

我的理由?如上所述,有很多方法可以使用谓词,但是对于ANTLR4缺乏经验但在目标语言方面经验丰富的工程师来说,可读性和可维护性,我会考虑这种方法。在我的环境中,我经常将ANTLR项目交给工程师,他们只是遵循我建立的模式,并且不了解ANTLR。这对他们来说更容易理解。