ANTLR4:通常可以验证解析器规则的各个部分吗?

时间:2013-08-06 13:45:28

标签: antlr antlr4

在使用ANTLR4时,我不断回到同样的问题 - 如何在解析器中实现算法规则验证。

例如,我需要解析器在匹配规则之前验证写入“月日”的日期的“年”部分。我已经知道我可以使用谓词执行此操作,如下所示:

date :
    {isYear(_input.LT(3).getText())}?
        month  day=INTEGER  year=INTEGER     { ... }

但是这个解决方案并不通用,因为它依赖于规则month总是一个令牌长。

我以为我已经通过将规则改为此来找到解决此问题的方法:

date :  month  day=INTEGER  yearInt     { ... } ;

yearInt returns [int i]
     :   {isYear(_input.LT(1).getText())}?
             yr=INTEGER                 { $i = $yr.int; }
     ;

不幸的是,即使isYear("6")失败,这个语法也会将“7月11日6”作为日期传递。当我在XXParser.java中为yearInt()追踪ANTLR生成的代码时,我看到它调用

throw new FailedPredicateException(this, "isYear(_input.LT(1).getText())");

然后代码继续并接受yearInt()

这是一个ANTLR错误,还是我的错误?是否有一种“正确”的方式来编写需要验证规则部分的语法?

1 个答案:

答案 0 :(得分:1)

尝试

date :
    month  day=INTEGER  year=INTEGER {isYear($year)}?<fail="A sensible error msg"> { ... }
;

date :
    month  day=INTEGER  year=INTEGER {if ( ! isYear($year) ) 
                                       notifyErrorListeners("A sensible error msg");
                                     }     
    { ... }
;

其中一个会产生更明智的错误信息。 notifyErrorListeners()建立错误,但是就正在进行的解析而言,解析“成功”。 {isYear($一年)}?将失败,并做更多寻找匹配。

我承认我实际上没有尝试过这段代码。也许你需要$ year.text而且我不确定fail选项和notifyErrorListeners()在C#版本和Java版本中是否有效。

乔治