在使用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错误,还是我的错误?是否有一种“正确”的方式来编写需要验证规则部分的语法?
答案 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版本中是否有效。
乔治