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

如何让Bison生成的yytname外部可见?有无更优获取标签名表的方法?

更好的获取Bison标签名表(yytname)的方法

你的sed workaround确实能搞定问题,但确实不够优雅——毕竟后期修改生成的代码,搞不好哪天Bison更新个版本,生成的代码结构变了,sed命令就失效了。这里有几个更原生、更可靠的方案:

方案一:通过宏直接控制yytname的可见性

Bison生成代码时,会用YYSTATIC宏来修饰yytname这类内部变量。默认情况下YYSTATIC被定义为static,但你可以在Bison源文件的开头重新定义这个宏,让它为空,这样生成的yytname就不会带有static属性:

%{
// 在Bison的%{ ... %}代码块中添加这个定义
#define YYSTATIC
%}

// 你的token定义、语法规则等
%token TAG SCORE
%%
// ... 你的语法规则实现
%%

这样生成的chess.tab.c里,yytname的声明就会变成:

const char *const yytname[] = { "$end", "error", "$undefined", "TAG", "SCORE", ... };

直接可以被其他编译单元访问,完全不需要sed这类后处理步骤。

方案二:封装安全的访问接口(最推荐)

如果你不想暴露全局的yytname(毕竟全局变量容易带来命名冲突或意外修改的风险),可以在Bison生成的代码里封装一个获取token名称的函数,然后在头文件中声明它供外部调用。

在Bison源文件最后一个%%之后的用户代码区添加:

%%
// 这里可以放你的yylex、yyerror等实现代码

// 自定义获取token名称的函数
const char* get_token_name(int token_id) {
    // YYTOKENS是Bison自动生成的宏,表示token的总数量
    if (token_id >= 0 && token_id < YYTOKENS) {
        return yytname[token_id];
    }
    // 处理无效token的情况,返回友好提示
    return "<unknown token>";
}

然后在你的头文件(比如用Bison的-d选项生成的chess.tab.h)中添加这个函数的声明:

#ifndef CHESS_TAB_H
#define CHESS_TAB_H

// 保留Bison自动生成的其他声明(比如YYSTYPE、token常量定义等)
extern const char* get_token_name(int token_id);

#endif

这样外部代码只需要调用get_token_name()就能拿到对应token的名称,既避免了直接访问内部变量,还能添加参数合法性检查,更安全也更符合代码封装的原则。

方案三:使用Bison的纯解析器模式(适用于多线程场景)

如果你的项目需要多线程支持,可以开启Bison的纯解析器模式(%define api.pure full)。在这种模式下,Bison会把yytname设置为全局可见(因为纯解析器不会依赖静态内部状态),不过这个模式会改变解析器的调用方式,需要你调整yylex等函数的参数传递逻辑。

在Bison源文件开头添加:

%define api.pure full

生成的代码中yytname就会是全局可访问的。不过这个方案更适合本来就需要纯解析器的场景,如果只是为了访问yytname,前面的方案二更合适。

内容的提问来源于stack exchange,提问作者A. P. Damien

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:59:18