# 错误恢复

框架中的`_parse`函数（位于`syntax/src/parser_ll.rs`）已经实现了一部分，然而尚未实现错误恢复的功能，遇到错误时会直接`unimplemented!()`，这是大家需要完成的实验任务。

在lecture4中，我们介绍了应急恢复和短语层恢复的方法。这里，我们使用一种介于二者之间的错误恢复方法：与应急恢复的方法类似，当分析非终结符$$A$$时，若当前输入符号$$a \notin Begin(A)$$，则先报错，然后跳过输入符号串中的一些符号，直至遇到$$Begin(A) \bigcup End(A)$$中的符号:

* 若遇到的是$$Begin(A)$$中的符号，可恢复分析A，即可以选择一个左端为$$A$$的产生式来分析它
* 若遇到的是$$End(A)$$中的符号，则A分析失败，返回`StackItem::_Fail`，继续分析$$A$$后面的符号

这个处理方法与应急恢复方法的不同之处在于:

* 我们用集合$$Begin(A) = {s | PS\[A， s]非空}$$(其中，$$PS$$为预测分析表)来代替$$First(A)$$。由于$$First(A) \in Begin(A)$$，我们能少跳过一些符号
* 我们用集合$$End(A) = Follow(A) \bigcup F$$(其中，F为`_parse`函数传入的最后一个参数)来代替$$Follow(A)$$。由于$$F$$集合包含了$$A$$各父节点的$$Follow$$集合，我们能少跳过一些符号，同时由于结束符(`_Eof`)必然属于文法开始符号的$$Follow$$集合，本算法无需额外考虑因读到文件尾而陷入死循环的问题。

另外，当匹配终结符失败时，只报错，但不消耗此匹配失败的终结符，而是将它保留在剩余输入串中。这个逻辑已经在`_parse`函数中实现。
