Bison中用%code provides{}定义yyerror出现多重定义报错怎么办
报错根因
%code provides {}块的内容会被完整插入Bison生成的*.tab.h头文件中。你在这个块里直接写了yyerror的函数定义(而非声明),而bas.tab.c和lex.yy.c两个编译单元都引入了该头文件,会各自编译生成一份yyerror的函数实现,链接阶段必然触发多重定义错误。
Bison手册提到provides块适合放对外暴露的声明,指的是函数声明、类型定义、宏这类可在头文件中重复出现的内容,并非指函数实现可以放在这里。
修复方案
将yyerror的声明保留在%code provides块中,把函数实现移到仅会被编译进bas.tab.c的代码段即可,修改后的.y文件核心代码如下:
%define parse.error detailed %define api.pure %{ #include <stdio.h> union YYSTYPE; int yylex(union YYSTYPE *); %} %code provides { // 头文件中仅放函数声明 void yyerror (char const *s); } %union { int ival; char *sval; } %token <ival> INT "integer" %token <sval> STR "string" %% expr: INT | STR; %% // 函数实现放在生成的c文件代码区,仅编译一次 void yyerror (char const *s) { fprintf (stderr, "%s\n", s); } int main() { return yyparse(); }
- 临时兼容方案:如果一定要把函数实现放在
%code provides块中,可以给函数加static修饰,让每个编译单元生成私有的函数副本,不会触发链接冲突。但这种方式会生成重复代码,若函数内存在静态变量还可能引发逻辑问题,不推荐常规使用。
修改后重新执行make即可正常编译,扫描器中调用yyerror的逻辑也能正常找到函数声明,不会报编译错误。
内容的提问来源于stack exchange,提问作者Christian Carter
相关产品推荐
相关产品推荐

