编译器设计中布尔表达式和控制语句的后向填充是什么?
执行语法制导翻译的最简单方法是使用两遍。首先,为输入构建语法树,然后以深度优先的顺序遍历树,完成定义中给出的翻译。
在单遍生成布尔表达式和控制流语句代码的主要问题是,在单遍过程中,我们无法理解在生成跳转语句时控制应该跳转到的标签。它可以通过生成一系列分支语句来解决这个问题,这些语句的跳转目标暂时未定义。
每个这样的语句将被放在一个 goto 语句的记录中,其中标签将在确定适当标签时填充。它可以称这种后续的标签填充为后向填充。
布尔表达式的后向填充
它可以构建一个适合在自底向上解析期间生成布尔表达式代码的翻译方案。语法中的非终结符标记 M 会在适当的时候触发一个语义动作,来获取要创建的下一个指令的索引。语法如下:
B → B1|| MB2|B1&& MB2|! B1|(B1)|E1rel E2|True|False
M → ϵ
翻译方案如下:
B → B1|| MB2 | {backpatch (B1. falselist, M. instr); B.truelist = merge (B1.truelist, B2.truelist); B.falselist =B2.falselist;} |
B → B1&& MB2 | {backpatch (B1. truelist, M. instr); B.truelist = B2.truelist; B.falselist = merge (B1. falselist, B2.falselist);} |
B → ! B1 | { B.truelist = B1.falselist; B.falselist = B1.truelist;} |
B → (B1) | { B.truelist = B1.truelist; B.falselist = B1.falselist;} |
B → E1 rel E2 | { B.truelist = makelist(nextinstr); B.falselist = makelist(nextinstr + 1); append ('if' E1. addr relop E2. addr 'goto-'); append ('goto-');} |
B → True | { B.truelist = makelist(nextinstr); append ('goto-');} |
𝐁 → 𝐅𝐚𝐥𝐬𝐞 | { B.falselist = makelist(nextinstr); append ('goto-');} |
𝐌 →∈ | {M.instr = nextinstr;} |
控制流语句
现在它可以使用后向填充在一遍中翻译控制流语句。考虑以下语法生成的语句:
S → if (B)then S | if (B)then S else S |while (B)then do
S| begin L end |A;
L → L; S | S
这里 S 表示语句,L 表示语句列表,A 表示赋值语句,B 表示布尔表达式。应该还有其他产生式,包括
- 后向填充 104 到指令 102 后。
100− if x < 100 goto -
101− goto -
102− if x > 200 goto 104
103− goto -
104− if x! = y goto-
105− goto-
- 后向填充 102 到指令 101 后
100− if x < 100 goto -
101− goto 102
102− if y > 200 goto 104
103− goto -
104− if x! = y goto-
105− goto-
给出了产生式,但是,它足以说明用于翻译控制流语句的技术。