编译Makefile时遇链接错误:未定义main等符号引用问题
搞定YACC/Bison解析器的链接错误
嘿,你这是编译YACC/Bison生成的解析器时碰到了典型的链接阶段问题,我帮你逐个拆解解决:
首先得说,你单独执行gcc parser.tab.o -o parser.tab只链接了单个目标文件,但解析器需要依赖词法分析器、自定义函数、程序入口这些模块,缺了它们就会报一堆未定义引用,咱们一个个来处理:
1. 「未定义对`main'的引用」
- 为啥会这样?YACC/Bison生成的
parser.tab.c默认不带main函数——它只负责解析语法,程序入口得你自己加。 - 怎么 fix:
- 要么直接在你的语法文件(比如
parser.y)里加个main函数,比如:%{ #include <stdio.h> // 先声明要用的函数 int yylex(void); void yyerror(const char *s); %} // ... 你的语法规则 ... %% // ... 规则对应的动作代码 ... %% // 加在这里就行 int main() { printf("开始解析...\n"); return yyparse(); } - 要么单独写个
main.c文件实现入口,编译的时候把它的目标文件也带上:gcc parser.tab.o main.o -o parser
- 要么直接在你的语法文件(比如
2. 「未定义对`yylex'的引用」
- 原因很简单:
yylex是词法分析器的入口,一般是Flex/Lex帮你生成的(比如生成lex.yy.c),你没把这个文件的目标文件链接进来。 - 解决步骤:
- 先确保你已经用Flex编译了词法文件(比如
lexer.l):flex lexer.l gcc -c lex.yy.c -o lex.yy.o - 然后把
lex.yy.o加到链接命令里:gcc parser.tab.o lex.yy.o -o parser
- 先确保你已经用Flex编译了词法文件(比如
3. 「未定义对`execute'的引用」
- 这个
execute是你自己在语法规则里调用的自定义函数对吧?它的实现不在parser.tab.c里,你得把包含它的文件也编译链接进来。 - 怎么弄:
- 找到定义
execute的C文件(比如util.c),先编译成目标文件:gcc -c util.c -o util.o - 链接的时候带上这个文件:
gcc parser.tab.o lex.yy.o util.o -o parser
- 找到定义
4. 「未定义对`yyerror'的引用」
- YACC/Bison只会声明
yyerror函数用来报语法错,但不会给你实现,得你自己写。 - 解决办法:
- 要么在语法文件里加个实现,比如:
void yyerror(const char *s) { fprintf(stderr, "哎呀,语法出错啦:%s\n", s); } - 要么写在单独的文件里,编译后一起链接就行。
- 要么在语法文件里加个实现,比如:
省心建议:整个Makefile自动搞定
手动敲命令太麻烦,整个Makefile一键编译不香吗?给你个模板:
CC = gcc YACC = bison # 要是用yacc就改成yacc LEX = flex # 最终生成的可执行文件 TARGET = parser # 依赖的所有目标文件 OBJS = parser.tab.o lex.yy.o util.o main.o all: $(TARGET) $(TARGET): $(OBJS) $(CC) $^ -o $@ # 生成YACC的C文件和头文件 parser.tab.c parser.tab.h: parser.y $(YACC) -d parser.y # -d是生成头文件,给Flex用 # 生成Flex的C文件,依赖YACC的头文件 lex.yy.c: lexer.l parser.tab.h $(LEX) lexer.l # 通用编译规则,把所有.c编译成.o %.o: %.c $(CC) -c $< -o $@ # 清理生成的文件 clean: rm -f $(TARGET) $(OBJS) parser.tab.c parser.tab.h lex.yy.c
以后只要敲make就能自动编译,make clean就能把生成的文件都删掉,省事多了~
内容的提问来源于stack exchange,提问作者Wang Yidu
相关产品推荐
相关产品推荐

