这是涉及翻译的大型家庭作业的一小部分。
基本上,我有一个操作,当完成某些事情时:
integer A, B, C
我想通过创建3个变量的过程实际运行。
目前在yacc文件中:
declare:
INT VAR { $$ = createvar(INT_T, $2); }
| FLT VAR { $$ = createvar(FLT_T, $2); }
;
其中createvar()
是创建变量的中间代码生成的一部分。问题是我想允许VAR
成为逗号分隔的列表,而且我真的迷失了该怎么做。我已经尝试在yacc文件中创建一个var_list,我想我可以找到一些不起眼的方法。但是,我希望尽可能多地重用代码,我认为这可能是一种递归方式。
var_list:
VAR { $$ = $1; }
| var_list ',' VAR { $$ = ????; }
;
有人可以推荐一些方法为列表中的每个值调用createvar()
吗?
答案 0 :(得分:1)
让我们从头开始,在自下而上的解析器的情况下是底部。
var_list
将成为某种列表,它将采用某种append()
方法。它需要在首次出现的地方创建,即生产
var_list ::= VAR
所以那里的行动就像是
{
$$ = new VariableList();
$$->append(create_var($1));
}
现在您已经启动了列表,它将附加到其他生产
| var_list ',' VAR
所以那里的动作就像
{
$1->append(create_var($3));
$$ = $1;
}
然后你在这里处理清单:
declaration ::= INT var_list
{
// process elements of the var_list $2 and assign them the type INT
}
同样对于FLT案例。
答案 1 :(得分:0)
简单的方法是在var_list
规则中创建名称列表:
var_list:
VAR { $$ = create_singleton_list($1); }
| var_list ',' VAR { $$ = append_to_list($1, $3); }
并在declare
规则中运行它:
declare:
INT var_list { $$ = create_vars_from_list(INT_T, $2); }
| FLT var_list { $$ = create_vars_from_list(FLT_T, $2); }
当然,您需要担心列表的内存管理,以确保它们能够正确清理。
另一个偶尔有用的技巧是使用一个继承属性,bison只有有限的支持 - 你可以使用适当定位的嵌入式操作将它们显式放在解析器堆栈上,然后使用{{1 }}:
$0
要想做到这一点非常棘手,并且需要明确的演员表(危险)并且要小心谨慎。或者,您可以使用btyacc,它直接支持此功能:
declare:
INT { $<type>$ = INT_T; } var_list
| FLT { $<type>$ = FLT_T; } var_list
var_list:
VAR { createvar($<type>0, $1); }
| var_list ',' VAR { createvar($<type>0, $3); }