2

在使用 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; }
     ;

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

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

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

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

4

1 回答 1

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)}?将失败并做更多的寻找匹配。

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

乔治

于 2013-08-22T01:03:25.023 回答