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

编译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
      

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:32:12