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

YACC计算器编译器编译报错:无法识别EAttr、IDAttr、Val类型

YACC计算器编译器编译报错:无法识别EAttr、IDAttr、Val类型

我来帮你拆解这个编译错误的根源,其实问题出在不该在flex文件里直接包含Bison的.y文件,再加上类型定义的作用域问题,才导致编译器找不到EAttr、IDAttr和Val这些类型。

核心原因分析

你的calc-lex.l文件第5行直接include了calc-ambiguo.y,但Bison的.y文件里包含大量Bison专属的伪指令(比如%union、%{、%}),这些都不是合法的C代码。当C编译器处理lex.yy.c时,会把.y文件的内容原封不动展开,引发两个关键问题:

  1. C编译器不认识%{和%}标记,会错误解析这两个标记之间的C代码(也就是你定义IDAttr、EAttr的部分);
  2. %union的定义会被编译器提前读取,但此时EAttr、IDAttr、Val的类型定义还没被加载,所以报出“未知类型名”的错误。

分步解决方法

我们需要把共享的类型定义提取到公共头文件,彻底避免直接包含.y文件的操作:

步骤1:创建公共头文件(比如calc-shared.h)

把所有需要在.y和.l之间共享的类型、声明都放到这个文件里,保证两边的类型定义完全一致:

#ifndef CALC_SHARED_H
#define CALC_SHARED_H

// 先引入symtab.h,确保Val类型被正确定义
#include "symtab.h"

// 表达式属性结构体
typedef struct {
    Val value;
    char* type;
} EAttr;

// 变量属性结构体
typedef struct {
    Val value;
    char* type;
    char* lexeme;
} IDAttr;

#endif // CALC_SHARED_H

步骤2:修改calc-ambiguo.y文件

移除原来%{ ... %}块里的IDAttr和EAttr定义,替换成引入公共头文件:

%{
#include "calc-shared.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>

Table *t;

void yyerror(const char *s) {
    fprintf(stderr, "%s\n", s);
    exit(1);
}

int yylex(void);
%}

%union {
    char* lexeme;
    EAttr eattr;    // 现在编译器能识别EAttr了
    char* type;
    IDAttr idattr;  // 同理识别IDAttr
    Val value;      // Val也能通过公共头文件找到定义
}

步骤3:修改calc-lex.l文件

把原来包含calc-ambiguo.y的行,替换成引入公共头文件:

// 删掉原来的 #include "calc-ambiguo.y"
#include "calc-shared.h"

// 剩下的lex代码保持不变...

步骤4:重新编译

运行你原来的编译命令即可,这次编译器就能正确识别所有类型了:

make
# 或者分步执行
flex calc-lex.l; bison -vd calc-ambiguo.y; gcc calc-ambiguo.tab.c lex.yy.c symtab.c -ly -ll

额外注意事项

  • 永远不要在flex的.l文件或普通C文件里直接包含Bison的.y文件,.y是给Bison工具处理的,不是给C编译器直接解析的;
  • 所有需要在.y和.l之间共享的类型、宏、函数声明,都要放到公共头文件里,这样能避免类型不匹配、作用域找不到的问题;
  • 确保symtab.h里的Val定义没有语法错误,且被公共头文件正确引入。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 09:34:32