如何从 LALR 语法中的 Bison 错误中恢复?

问题描述 投票:0回答:1

我正在尝试找出如何正确从 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;
}

c bison yacc
1个回答
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
将之前解析的行通过错误恢复传递到之后解析的行。

© www.soinside.com 2019 - 2024. All rights reserved.