【发布时间】:2016-05-26 00:05:21
【问题描述】:
我正在阅读 Kenneth Louden 的“编译器构造、原理和实践”一书,并试图了解 Yacc 中的错误恢复。
作者给出了一个使用以下语法的例子:
%{
#include <stdio.h>
#include <ctype.h>
int yylex();
int yyerror();
%}
%%
command : exp { printf("%d\n", $1); }
; /* allows printing of the result */
exp : exp '+' term { $$ = $1 + $3; }
| exp '-' term { $$ = $1 - $3; }
| term { $$ = $1; }
;
term : term '*' factor { $$ = $1 * $3; }
| factor { $$ = $1; }
;
factor : NUMBER { $$ = $1; }
| '(' exp ')' { $$ = $2; }
;
%%
int main() {
return yyparse();
}
int yylex() {
int c;
/* eliminate blanks*/
while((c = getchar()) == ' ');
if (isdigit(c)) {
ungetc(c, stdin);
scanf("%d\n", &yylval);
return (NUMBER);
}
/* makes the parse stop */
if (c == '\n') return 0;
return (c);
}
int yyerror(char * s) {
fprintf(stderr, "%s\n", s);
return 0;
} /* allows for printing of an error message */
产生如下状态表(后面称为表5.11)
减少中的数字对应于以下产生式:
(1) command : exp.
(2) exp : exp + term.
(3) exp : exp - term.
(4) exp : term.
(5) term : term * factor.
(6) term : factor.
(7) factor : NUMBER.
(8) factor : ( exp ).
那么Louden博士举个例子:
考虑如果将错误产生式添加到 yacc定义
factor : NUMBER {$$ = $1;} | '(' exp ')' {$$=$2;} | error {$$ = 0;} ;考虑第一个错误输入 2++3 与前面的示例一样(我们继续使用表 5.11,尽管额外的错误产生导致表略有不同。)与之前一样,解析器将 达到以下几点:
parsing stack input $0 exp 2 + 7 +3$现在
factor的错误生成将提供 error 是 状态 7 中的合法前瞻和 error 将立即转移 到堆栈上并减少到factor,导致值 0 为 回来。现在解析器已经到了以下点:parsing stack input $0 exp 2 + 7 factor 4 +3$这是正常情况,解析器会继续执行 通常到最后。效果是将输入解释为2+0+3 - 两个 + 符号之间的 0 在那里,因为这是插入 error 伪标记的位置,以及错误的操作 生产,error被视为等价于具有价值的因素 0.
我的问题很简单:
通过查看语法,他如何知道为了从这个特定错误 (2++3) 中恢复,他需要将 error 伪标记添加到 factor 产生式?有没有简单的方法来做到这一点?或者唯一的方法是使用状态表计算多个示例,并认识到这个特定的错误将发生在这个给定的状态,因此如果我将 error 伪标记添加到某个特定的生产错误将得到修复。
感谢任何帮助。
【问题讨论】: