Bison使用%code requires时YY_DO_BEFORE_ACTION未定义原因
问题产生原因
这个错误是依赖方向错误+循环include触发Flex条件编译逻辑异常导致的,核心逻辑如下:
%code requires块的内容会被Bison直接放到生成的对外头文件prologue.tab.h的最开头,所有include这个头的代码都会先执行requires块里的内容;而普通无标识的%code块内容只会被放到Bison生成的.c实现文件中,不会进入对外头文件。- 将include语句放入
%code requires块后,会触发两个关键问题:- 块内写了
#include "prologue.tab.h",属于在Bison生成的头文件内部自引用,会触发无意义的循环include - 块内写了
#include "prologue.h"(Flex生成的lexer头文件),完全反转了依赖方向:正常依赖关系是Flex生成的lexer代码依赖Bison生成的parser头文件,反向在parser头中引入lexer头会破坏Flex生成代码的宏定义顺序
- 块内写了
- Flex生成的
lex.yy.c中,YY_DO_BEFORE_ACTION、YY_NEW_FILE这两个宏是在引入用户自定义头文件区块之后,通过条件编译判断未定义才会生成默认实现。当在Bison头文件中提前引入Flex生成的prologue.h时,会提前触发Flex头中的条件编译守卫,导致后续lex.yy.c中本该定义这两个宏的代码被跳过,最终编译时提示宏未定义。 - 未使用
%code requires时,所有include语句都只存在于Bison生成的.c文件中,编译lex.yy.c时不会提前加载Flex头文件触发守卫,因此宏可以正常定义,编译不会报错。
修复方案
按照以下步骤调整代码即可:
- 清理
%code requires块的内容,该块仅放%union、token定义需要的最小依赖,禁止放入任何生成文件的include语句:%code requires { // 仅保留union依赖的标准库头,比如在union中用了std::string就保留<string>引入 #include <string> } - 将其他依赖引入语句移到普通
%code块(仅在Bison生成的.c文件中生效,不会进入对外头文件),移除冗余的自引用include:
注意:普通%code top{ #include <iostream> #include <fstream> #include <stdio.h> #include "prologue.h" // Flex生成的头仅在parser实现中引入即可,不需要对外暴露 void yyerror (char const *s); }%code块和%code top块中都不需要再写#include "prologue.tab.h",Bison生成实现文件时会自动把自身头的引入放在合适位置,手动自引入只会触发循环引用问题。 - 调整完成后先执行
make clean清除旧的生成文件,再重新make即可正常编译。
内容的提问来源于stack exchange,提问作者afarley
相关产品推荐
相关产品推荐

