YACC解析器中YYEOF的正确使用:EOF触发仍报yyerror问题
问题原因
输入文件结束时,解析器的当前语法状态无法匹配EOF标记,导致触发yyerror():
- 原语法规则仅允许
YYEOF作为起始符号A的单独选项,处理完所有带换行的表达式后,解析器处于已匹配A的状态,此时遇到EOF无法匹配任何有效产生式,触发错误。 - 若输入文件最后一行无换行符,解析器处理完最后一个表达式后遇到EOF,也无法匹配
A B '\n'规则,同样触发错误。
修复方案
1. 调整Yacc语法规则,适配EOF和末尾无换行场景
修改Yacc代码的语法规则,明确支持末尾表达式无换行,并在EOF到来时正常终止:
%{ #include <stdio.h> #include <stdlib.h> int yylex(); void yyerror(); extern FILE* yyin; %} %start program %token INTEGER %left '+' '-' %left '*' '/' %% program : lines YYEOF { exit(0); } ; lines : lines expr '\n' { printf("%d\n", $2); } | lines expr { printf("%d\n", $2); } // 处理最后一行无换行的情况 | /* 空规则,匹配初始状态 */ ; expr : expr '+' expr { $$ = $1 + $3; } | expr '-' expr { $$ = $1 - $3; } | expr '*' expr { $$ = $1 * $3; } | expr '/' expr { $$ = $1 / $3; } | '+' expr { $$ = $2; } | '-' expr { $$ = -$2; } | '(' expr ')' { $$ = $2; } | INTEGER ; %% void yyerror() { fprintf(stderr, "Error\n"); exit(0); } int main(int argc, char** argv) { yyin = fopen(argv[1], "r"); yyparse(); }
2. 简化Lex的EOF处理(可选)
Lex中<<EOF>> return YYEOF;可替换为直接返回0(YYEOF本质就是0),效果一致:
%{ #include <stdio.h> #include <stdlib.h> #include "y.tab.h" void yyerror(); extern int yylval; %} %% [ \t] ; [0-9]+ { yylval = atoi(yytext); return INTEGER; } [-+*/\n()] return *yytext; <<EOF>> return 0; . yyerror(); %% int yywrap() { return 1; }
修复原理
- 新增
program起始规则,明确要求解析完所有表达式(lines)后遇到EOF立即正常退出,避免EOF无法匹配的问题。 lines规则新增lines expr选项,支持最后一行表达式无换行符的场景,覆盖所有输入情况。
内容的提问来源于stack exchange,提问作者neversettle evolve
相关产品推荐
相关产品推荐

