如何让Bison使用外部自定义Token定义并避免重定义错误?
兄弟我太懂你这种糟心情况了——自己辛辛苦苦写了tokens.h定义好所有Token枚举,结果一跟Bison的生成文件结合就报重定义错误,查文档还找不到明确说明,简直头大。其实Bison完全支持直接用外部的Token定义,只是这个技巧藏得有点深,我给你一步步讲明白:
第一步:给Bison文件加关键配置,禁用自动Token生成
你需要在Bison语法文件(.y)的最开头加上这段配置,明确告诉Bison:别自己瞎生成Token定义,用我写的tokens.h就行:%code requires { #include "tokens.h" } // 核心配置:禁止Bison生成自己的Token枚举 %define api.token.enum false // 让Bison直接使用你定义的Token原名(比如T_PLUS),不用加额外前缀 %define api.token.prefix ""这里的
%code requires块会把tokens.h自动包含到Bison生成的parser.tab.h里,保证Bison能识别你定义的Token枚举;而api.token.enum false是解决重定义的关键,直接从根源上关掉Bison自动生成Token枚举的功能。第二步:在Bison里声明你要用的Token
接下来,在Bison文件里用%token声明所有你要用到的Token,直接用tokens.h里的枚举名就行,不用额外指定数值(Bison会自动从tokens.h里读取对应的值):%token T_PLUS T_MINUS T_STAR T_SLASH %token T_LPAREN T_RPAREN %token T_NUMBER T_IDENTIFIER第三步:Flex文件直接对接外部Token
你的Flex文件(.l)里同样包含tokens.h,匹配到对应符号时直接返回枚举里的Token值就好,不用再依赖Bison生成的宏:%{ #include "tokens.h" #include "parser.tab.h" %} %% "+" { return T_PLUS; } "-" { return T_MINUS; } "*" { return T_STAR; } "/" { return T_SLASH; } "(" { return T_LPAREN; } ")" { return T_RPAREN; } [0-9]+ { return T_NUMBER; } [a-zA-Z_][a-zA-Z0-9_]* { return T_IDENTIFIER; } %%最后提个小注意事项
如果你之前已经生成过旧的parser.tab.h,记得先把这些旧文件删掉再重新编译,避免残留的旧定义搞出奇怪的冲突。另外你的tokens.h已经加了头文件保护(#ifndef TOKENS_H那些),这点做得很对,能防止多次包含的问题。
你之前试过的“映射Bison Token到外部定义”的方法确实能用,但上面这种方式才是更优雅的解决方案——相当于让Bison完全接入你自己的Token体系,不用做额外的映射工作,后期维护起来也更省心。
内容来源于stack exchange

