能否为Bison语法规则创建类似宏的列表规则生成机制?
Bison批量生成列表规则的宏机制问题
现有语法示例
当前的Bison语法规则大致如下:
command : TOK_A a_command { $$.obj_a = std::move($2); } | TOK_B b_command { $$.obj_b = std::move($2); } | TOK_C c_command { $$.obj_c = std::move($2); } ....
各子命令的定义示例:
a_command: TOK_A1 a_params1 | TOK_A2 a_params2| ... b_command: TOK_B1 b_params1 | TOK_B2 b_params2 | ... c_command: TOK_C1 c_params1 | TOK_C2 c_params2 | ...
需求说明
当前语法只能解析TOK_A TOK_A1 (123)这类单命令行,现在需要支持一行内多个同类型子命令,比如:
TOK_A TOK_A1 (123) TOK_A1 (234) TOK_A1 (356) ... TOK_A TOK_A2 ("str") TOK_A2 ("str1") TOK_A2 ("st2") ...
当前可行但繁琐的方案
要实现这个需求,可以为每个命令单独定义列表规则,比如:
a_command_list : a_command | a_command_list a_command; b_command_list : b_command | b_command_list b_command; c_command_list : c_command | c_command_list c_command;
但每个命令都要写一遍这类规则,重复工作量大。
问题
想知道Bison是否支持类似C宏的机制,比如定义一个模板宏:
#define list_command(cmdName) cmdName##_command_list : cmdName##_command | cmdName##_command_list cmdName##_command;
然后通过list_command(a)这类调用批量生成列表规则,避免重复编写?
解决方案
Bison原生支持m4预处理器,可以用它实现这种批量生成规则的需求,具体步骤如下:
- 定义m4宏:在Bison语法文件开头添加m4的宏定义,替代C宏的写法(m4的宏语法和C不同):
define(`list_command', `$1_command_list: $1_command | $1_command_list $1_command;')
- 批量生成规则:直接调用宏生成对应命令的列表规则:
list_command(a) list_command(b) list_command(c)
这会自动展开为:
a_command_list: a_command | a_command_list a_command; b_command_list: b_command | b_command_list b_command; c_command_list: c_command | c_command_list c_command;
- 修改主command规则:把原来的单个子命令换成对应的列表规则,并调整动作代码(需要把语义值从单个对象改成容器,比如
std::vector):
command : TOK_A a_command_list { $$.obj_a_list = std::move($2); } | TOK_B b_command_list { $$.obj_b_list = std::move($2); } | TOK_C c_command_list { $$.obj_c_list = std::move($2); } ....
注意事项
- Bison默认启用m4预处理器,除非编译时加了
-no-preprocessor参数,所以不需要额外配置就能用。 - 如果宏里涉及特殊字符(比如
|、;),m4会自动处理,不需要额外转义。
内容的提问来源于stack exchange,提问作者Dmitry
相关产品推荐
相关产品推荐

