正文
ANTLR3完全参考指南读书笔记[08]
小程序:扫一扫查出行
【扫一扫了解最新限行尾号】
复制小程序
【扫一扫了解最新限行尾号】
复制小程序
前言
不要让用户被那些“专业术语”吓住!
用心设计的提示和反馈信息是软件设计者的“职业良心”。
内容
1 存在哪些错误?
2 美化错误提示
3 错误恢复策略
1 存在哪些错误?
在DSL语言开发周期内,首先需要设计文法,根据文法生成翻译器,然后输入语言样本测试翻译器的效果,以及根据存在的翻译问题调整翻译策略。这其中就可能存在两类错误:文法错误和语言样本错误。
在Parr将一些错误拉出来游街,以及盛赞ANTLR在错误提示和恢复方面的优异表现的描述中,可以观察到一些错误提示和恢复的策略和惯例:
(1)错误恢复是从语言样本中的语法错误中恢复过程,常通过修改输入符号或吃掉一些符号直到解析器到达识别了一个确定性的规则状态;
(2)应该极力避免级联错误提示信息,即每个语法错误只给出一条错误提示信息。
2 美化错误提示
打开ANTLR的-dfa选项,可以通过查看生成的DFA,了解识别器的决策和状态信息。
为实现美化的错误提示,在文法中覆盖BaseRecognizer的getErrorMesage()和getTokenErrorDisplay()方法。(文中要求覆盖displayRecognitionError()而不是getErrorMesage(),其实查看生成的代码可以产出前者会调用后者)。
一些内建的异常类
异常 | 说明 |
RecognitionException | 识别异常。ANTLR生成的识别器抛出异常的基类。记录错误发生时的输入流信息:识别器当前看到的符号(字符、Token或树节点)的索引,错误符号的指针、当前行、行内位置。 |
MismatchedTokenException | Token不匹配异常。指出解析器预期的特定符号当前未找到。记录额外的Token类型信息。 |
MismatchedTreeNodeException | 树节点不匹配异常。 与上一异常类似,指出树解析器预期的特定token类型节点未找到。 |
NoViableAltException | 无可行选项异常。识别器达到决策点,但向前看符号与所有选项均不一致。记录向前看DFA中决策号和状态号,同时记录做出此决策的一块文法。 |
EarlyExitException | 过早退出异常。识别(...)+ EBNF子规则时,只少匹配一个,但该规则没有匹配任何符号。记录DFA中决策号。 |
FailedPredicateException | 失败的谓词异常。语义谓词求值为false。记录规则名称和谓词文本。 |
MismatchedRangeException | 范围不匹配异常。范围如[a..z],未匹配范围中任何符号。记录范围中最小和最大元素。 |
MismatchedSetException | 集合不匹配异常。集合如{'a','b'},未匹配集合中任何符号。记录集合中所有符号。 |
MismatchedNostSetException | 非集合不匹配异常。非集合指用~操作符表示的集合的拟。与上一个异常类似。 |
ANTLR识别器不用字符串信息创建异常对象,只跟踪和记录必要的用于生成错误的现场信息。
基识别器类BaseRecognizer中多个报告错误方法可以生成本地的错误信息,不要指望从上面的异常类中getMessage()方法返回什么异常信息。
除异常信息外,可以在文法中用自定义动作提供错误信息。
一个重要的错误信息提示是指出发生错误时所用的解析规则(栈),一般方法是在文法@members中定义个错误信息栈,在对用户意义最清晰的规则中的@init/@after动作中分别执行入栈和出栈操作,同时在@memebers动作中覆盖getErrorMessage()方法,它使用该错误信息栈的peek()获取当前现场的提示信息。
错误零容忍:遇到第一个错误立即退出
需要在文法@members动作中覆盖mismatch()、recoverFromMismatchedSet()方法以及覆盖默认的@rulecatch。
覆盖@rulecatch动作会对所有规则产生影响,可以采用细粒度的规则级catch动作来执行手动恢复操作。
词法和树文法的错误与一般文法类似,区别仅在于处理的是字符和树节点。
3 错误恢复策略
站在巨人的肩膀上
ANTLR的错误恢复机制参考了Nikalaus Wirth的"Algorithms + Data Structures = Programs"(八卦一下:好像他靠这句话拿到图灵奖)、Rodney Topor的"递归下降解析器中错误恢复记录"和一些Josef Grosch在CoCo解析器生成器的一些思路。
本质上的思路是,识别器在遇到不匹配的符号错误时,先尽可能的尝试单个符号插入和删除是否可以恢复,如果不能,再吞掉一些符号直到向前看符号属于一个重新同步集(resynchronization set)后退出该规则。
重新同步集是输入符号的集合,这些符号可以合法的在当前规则和当前规则调用链中出现。