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文件的内容原封不动展开,引发两个关键问题:
- C编译器不认识
%{和%}标记,会错误解析这两个标记之间的C代码(也就是你定义IDAttr、EAttr的部分); %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
相关产品推荐
相关产品推荐

