You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 01:21:00