我正在尝试找出如何正确从 Bison 中的错误中恢复。问题是,当输入正确时,一切正常,直到输入错误为止。在这种情况下,它会将所有接下来的输入确定为不正确,即使它们是正确的。有谁知道如何解决这个问题吗?
%{
int yyerror(char *s);
int yylex(void);
//#define YYDEBUG 1
#include <stdio.h>
int linenum = 0;
%}
%token a_TOK b_TOK c_TOK d_TOK e_TOK f_TOK g_TOK h_TOK newline_TOK any_TOK
%%
X: S
| error newline_TOK { yyerrok; yyclearin; };
S: A B LF X;
A: a_TOK h_TOK | a_TOK b_TOK A c_TOK | a_TOK B c_TOK;
B: C D E;
LF: newline_TOK {
linenum += 1;
printf("Correct derivation - line %d!\n", linenum);
};
C: d_TOK | e_TOK;
D: f_TOK D | f_TOK;
E: B | g_TOK;
%%
int yyerror(char *s)
{
linenum += 1;
printf("Syntax error - line %d\n", linenum);
return 0;
}
int main(void)
{
#if YYDEBUG
yydebug = 1;
#endif
if(!yyparse())
printf("End of input reached\n");
return 0;
}
这是由两件事造成的:
顶级
X
规则不是递归的,因此在错误恢复之后,唯一有效的延续是输入的结尾。 EOF 以外的任何内容都会导致另一个错误(这将丢弃直到下一个换行符以恢复,然后重复该过程。)
你的递归
S
规则是(间接)右递归,因此必须先识别整个输入并将其压入堆栈,然后才能减少S
,从而消耗从右到左的行。再次强调,错误恢复只能在输入结束时发生。
解决方法是让你的顶级规则保持递归,并且(当你这样做时,虽然完全没有必要,只是更简单)摆脱
X
规则。所以你有
S : /* epsilon */
| S A B LF
| S error newline_TOK { yyerrok; yyclearin; }
;
现在从错误中恢复后,它可以解析更多
A B LF
行。
您可能认为错误产生中的
S
很奇怪,事实上,如果不对行为进行任何更改,则没有必要(可以删除),除非您想向消耗 S A B LF
的
$1
规则添加操作(也许将所有解析的行链接在一起形成某种列表或向量数据结构)。在这种情况下,需要错误产生中的
S
将之前解析的行通过错误恢复传递到之后解析的行。