一旦标号L定义时,我们将根据这条链回填那些待填转移目标的四元式。一般而言,假定用下面的产生式来定义标号语句
S→label S
label→i:
那么,当用label→i:进行归约时,应做如下的语义动作:
1.若i所指的标识符(假定为L)不在符号表中,则把它填入,置"类型"为"标号","定义否"为"已","地址"为nextstat。
2.若L已在符号表中但"类型"不为"标号"或"定义否"为"已",则报告出错。
3.若L已在符号表中,则把标志"未"改为"已",然后,把地址栏中的链首(记为q)取出,同时把nextstat填在其中,最后,执行回填。
翻译goto语句时,还有两点必须注意,第一:是相同名字的标号可以在不同名字作用域中定义。如:
(1) begin
(2) L:begin
(3) goto L;
(4) ……
(5) L:…
(6) end
(7) end
当在行(3)处理goto语句时,不知道L的作用域到底是哪个,(因为还没见到语句(5)),因此一定要延迟解决这个标号的使用。
另外有些转移标号是非法的,如下例:
(1) for i∶=1 to 10 do
(2) begin goto L;
(3) for j∶=1 to 20 do
(4) begin goto L;
… …
(n) L: end {for j}
end {for i}
处理到第(n)行后,第(4)行的goto目标得以解决。而第(2)行的goto L是非法的,但只有当循环关闭时才能确定。
还要注意的问题是转移出分程序或过程外的goto语句,编译程序需要很多额外的编码,比如要恢复和保留一些运行环境等,这在后面(第10章)介绍了运行环境时,可能会理解更深些。
|