gpt4 book ai didi

c - 我如何应对/创建/规避 Yacc/Bison 中处理多个 %types 的规则?

转载 作者:行者123 更新时间:2023-11-30 15:59:41 26 4
gpt4 key购买 nike

我正在尝试在 Yacc/Bison 中创建一个 LALR(1) 解析器,它可以接受具有灵活语法的命令。一个例子是通过调整室温( float )、 window 位置(整数)和吊扇(枚举)来控制房屋中的环境。示例(所需的)语法是:

set kitchen 22.5, den 0 24.0, bathroom fast 25, kitchen slow

我被困在如何处理规则中所谓的“room_arg”的堆叠数据上。我可以添加 room_arg arg输入%union声明,设置%type <arg> room_arg并制定“room_arg”规则:

room_arg:  TOK_CIELING_FAN { $$.fan = $1; }
| TOK_WINDOW { $$.window_position = $1; }
| TOK_THERMOSTAT { $$.temperature = $1; }

但是当涉及到将“room_arg”规则减少为“room_args”时 - 我必须弄清楚哪些堆栈项目是哪些。除此之外,特定房间(示例中的“厨房”)的“room_cmd”不需要在命令中进行分组,这增加了我的挑战。

更改命令的格式固然很好,但可惜这是不可能的。

有人可以建议实现策略,或者改进解析器逻辑以使事情变得更简单吗?

要批评的语法如下。

%{
typedef enum fan_setting_tag { OFF, SLOW, MEDIUM, FAST } fan_setting;

struct room_arg_tag {
int window_position;
fan_setting fan;
float temperature;
char * room_name;
} room_arg;
%}
%token TOK_ROOM
%token TOK_CIELING_FAN
%token TOK_WINDOW
%token TOK_THERMOSTAT
%token TOK_SET

%type <fan> TOK_CIELING_FAN
%type <window> TOK_WINDOW
%type <tempr> TOK_THERMOSTAT
%type <str> TOK_ROOM

%union {
int window;
float tempr;
fan_setting fan;
}

%%

command: /* empty */ | cmd command

cmd: TOK_SET room_cmds { execute_command( ... ); }

room_cmds: room_cmd
| room_cmd ',' room_cmds

room_cmd: TOK_ROOM room_args

room_args: room_arg
| room_arg room_args

room_arg: TOK_CIELING_FAN
| TOK_WINDOW
| TOK_THERMOSTAT

最佳答案

在这种情况下,您确实需要继承属性。您可以使用额外的操作来模拟它们,但不幸的是 yacc 和 bison 没有为您提供更直接地执行它们的方法( btyacc 提供语法糖使这变得更容易。)

基本上,您所做的就是使用嵌入操作来设置继承的属性,并使用 $0 在较低级别的规则中访问它们。

使用 btyacc 你会这样做:

%union {
int window;
float tempr;
fan_setting fan;
room_arg *room;
}

%token<fan> TOK_CIELING_FAN
%token<window> TOK_WINDOW
%token<tempr> TOK_THERMOSTAT
%token<str> TOK_ROOM

%type<room> room_cmds(<room>)
%type<> room_cmd(<room>), room_args(<room>), room_arg(<room>)

%%

command: /* empty */ | cmd command ;

cmd: TOK_SET room_cmds(new_room_arg()) { execute_command( ... ); } ;

room_cmds($room):
room_cmd($room) { $$ = $room; }
| room_cmd($room) ',' room_cmds($room) { $$ = $room; }
;

room_cmd($room): TOK_ROOM room_args($room) { $room->room_name = $1; } ;

room_args($room):
room_arg($room)
| room_arg($room) room_args($room)
;

room_arg($room):
TOK_CIELING_FAN { $room->fan = $1; }
| TOK_WINDOW { $room->window_position = $1; }
| TOK_THERMOSTAT { $room->temperature = $1; }
;

在 yacc 或 bison 中,这会变成这样:

cmd: TOK_SET { $$ = new_room_arg(); } room_cmds { execute_command(...)' } '
room_cmds:
room_cmd { $$ = $<room>0; }
| room_cmd ',' { $$ = $<room>0; } room_cmds { $$ = $<room>0; }
;
room_cmd: TOK_ROOM { $$ = $<room>0; } room_args { $<room>0->room_name = $1; }

等等,这很难做到正确(在正确的位置获得所有正确的类型)并且容易出错。

在这种特定情况下,您可以只使用全局变量(因为不涉及递归),但在更复杂的情况下效果不太好。

关于c - 我如何应对/创建/规避 Yacc/Bison 中处理多个 %types 的规则?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8527026/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com