yacc 程序错误处理

当解析器读输入流时,该输入流可能与语法文件中的规则不匹配。

解析器尽早检测问题。 如果在语法文件中有错误处理子例程,解析器可以允许重新输入数据、忽略坏数据或者初始化清除和恢复操作。 当解析器发现错误,例如,它可能需要收回语法分析树存储器、删除或者改动符号表条目并设置开关,以避免生成进一步的输出。

当出现错误时,解析器停止,除非您提供错误处理子例程。 要继续处理输入来找出更多错误,请在输入流中解析器能够尝试识别更多输入处重新启动解析器。 发现错误时重新启动解析器的一种方法是废弃错误后的一些标记。 然后试着在输入流的该处重新启动解析器。

yacc 命令为错误处理使用特殊的标记名称 error。 将规则文件中的此标记放在输入错误可能出现的地方,以便您就能提供恢复子例程。 如果在此位置出现输入错误,那么解析器将执行 error 标记的操作,而不是正常操作。

下面的宏可以被放在 yacc 操作中帮助进行错误处理:
描述
yyerror 使得解析器初始化错误处理
YYABORT 使得解析器返回值 1
YYACCEPT 使得解析器返回值 0
YY恢复 () 如果语法错误已检测到且解析器尚未完全恢复,那么返回值 1

为了阻止单个错误产生许多错误消息,解析器保持在错误状态直到它处理了错误后面的三个标记。 如果当解析器处于错误状态时,出现了另一个错误,解析器将废弃输入标记且并不产生消息。

例如,下面格式的规则:
stat  :  error ';'

告诉解析器,有错误时它应该忽略标记以及标记后面的所有标记,直到它找到下一个分号。 废弃错误后面和下一个分号前面的所有标记。 找到分号之后,解析器将减少此规则并执行与其关联的任何清除操作。

为纠错作准备

您也能够允许在交互环境中输入输入流的人员通过再次在数据流中输入行来更正任何输入错误。 后面的示例显示了这样做的一种方法。
input : error '\n'
        {
          printf(" Reenter last line: " );
         }
         input
       {
         $$ = $4;
       }
       ;
但是,在此示例中,解析器在错误后面的三个输入标记中仍处于错误状态。 如果已更正行在前三个标记中包含错误,那么解析器将删除标记而且并不产生消息。 要允许此情况,请使用后面的 yacc 语句:
yyerrok;

当解析器找到此语句时,它就离开错误状态,开始正常处理。 错误恢复示例则变成:

input : error '\n'
        {
          yyerrok;
          printf(" Reenter last line: " );
         }
         input
       {
         $$ = $4;
       }
         ;

清除预测标记

预测标记是解析器要检查的下一个标记。 当发生错误时,预测标记变成检测出错误处的标记。 但是,如果错误恢复操作包括查找再次启动处理的正确位置的代码,那么该代码必须也更改预测标记。 要清除预测标记,请在错误恢复操作中包含以下语句:
yyclearin ;