语法错误与恢复
复习
- 递归下降分析:每个非终结符一个函数
- 预测分析与移进归约分析:两类解析思路
- 语法分析要解决什么:判断结构与合法性
TL;DR
- 语法错误是常见且必须处理的情况
- 好的编译器会报告位置,并尽量继续分析
- 恢复策略有同步、插入、删除等
- 目标是尽量一次报出更多错误
正文
前面讲的都是“输入完全正确”时解析器怎么工作。可现实中,代码写错是家常便饭。语法分析器必须能发现错误、报告错误,并尽量继续。
只报第一个错,体验很差
最简单粗暴的做法是:一遇到语法错误就停下、报错、退出。
但这体验很糟。因为使用者一次往往写错好几处,如果每编译一次只报一个错,就得“改一个、编译一次、再改一个”地反复折腾。理想的编译器,应该尽量在一次编译里发现尽可能多的错误。
要做到这一点,解析器在报错之后不能立刻放弃,而要想办法恢复到某个可以继续的状态。
几种恢复策略
常见的恢复策略有:
- 恐慌模式:跳过一些输入,直到遇到一个“同步点”,比如分号、右花括号,然后从这里继续解析
- 短语级恢复:对出错的局部做小修补,比如删掉一个多余的词、或插入一个缺少的词,然后接着走
- 错误产生式:在文法里预先写好“常见错误”的规则,专门用来识别并处理这些错误
其中“恐慌模式”实现简单、不易陷入死循环,是最常用的一种。
报告也要清楚
发现错误之后,怎么报告同样重要。一条好的错误信息,至少应包含:
- 出错的位置(哪一行、哪一列)
- 大致是什么问题(比如“这里期望一个右括号”)
含混的报错会让使用者无从下手,甚至把人引向错误的方向。“发现错误”只是第一步,“帮人理解错误”才是最终目的。
到这里,语法分析这条线就走完了:从词序列,到语法树。下一章,我们看看这棵树具体长什么样、又要不要“修剪”一下。
思考题 1
为什么编译器遇到语法错误后,常常要“尽量继续分析”,而不是立刻停止?
思考题 2
常见的语法错误恢复策略有哪几种?
小结
知识点
- 语法分析必须处理错误输入
- 好的编译器会报告位置并尽量继续
- 恢复策略:恐慌模式、短语级恢复、错误产生式
- 错误信息要包含位置与问题说明
参考资料
- Wikipedia(zh):语法分析:错误检测与恢复
- Wikipedia(zh):编译错误:编译器报告的错误信息
思考题答案(仅供参考)
思考题 1
因为一次编译往往只报一个错,使用者就得反复“改一处、再编译”,效率很低。尽量继续分析,可以在一次编译中暴露更多错误,让使用者一次改完,体验和效率都更好。
思考题 2
常见有三种:恐慌模式(跳过输入到同步点再继续)、短语级恢复(局部插入或删除符号来修补)、错误产生式(在文法中预设常见错误规则来识别并处理)。
协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
封面图
设计师 | 南国微雪