# ch14-ir-control-比较复杂的控制流翻译
# 如何生成更短、更高效的代码?


- t3 = true的赋值不是必须的:我只要知道根据bool表达式跳转到哪即可
直接用布尔表达式改变控制流br
使用控制流跳转间接表明布尔表达式的值
实现思路:分工 合作
父节点为子节点准备跳转指令的目标标签
子节点通过继承属性确定跳转目标
P → S S → if (B) S1
- S知道B.true和B.false这两个继承属性
# 具体翻译方案

- 对于每一个B,都有B.true和B.false这两个继承属性(标签)
- 对于每一个S,都有S.next:当S内部发生控制流跳转,会跳转到哪
# 每一个产生式的三个继承属性如何生成

- P.code是综合属性,即S.code
- 可能会有跳转语句跳出S本身,所以需要有一个label:S.code翻译完之后紧接的下一条指令的位置
# 赋值语句的翻译
代表了表达式的翻译, 包括数组引用

没有S和B,不需要准备继承属性
# if语句的翻译

- label加在B.code和S~1~.code之间:作用:当我翻译B的时候,里面可能会有goto语句,如果B为true,就会goto到B.true这个label
- B.true:new label(),新建一个label
- B.false:S.next

蚂蚁老师的注释:

代码框架:

# 更复杂的if-else模式:

- B.true和B.false生成和放置的位置和之前的if-assign相似
- goto S.next是B.true之后,执行了S~1~.code,不执行S~2~.code,所以跳转到S.next
例子详解:

- S~11~和S~12~都继承了S~1~的next,S~1~和S~2~都继承了S的next
- S.code是根据上面的生成规则生成的,对应蚂蚁注释里的L1-L4
# while语句的翻译

蚂蚁的注释:


蚂蚁的注释:

考试的时候可能是二分查找之类的
产生式与语法规则:


取反的话跳转方向换一下就行:

# 短路求值

- B1为true,意味着B为true
- B1为true并且B2为true,整个为true
- B2为false,意味着B1也为false,所以整个为false

- B1为true,意味着还需要看B2
- 如果B1为false,意味着整个为false
- B2决定最后B为true还是false

例子


- 如果x < 100 ,意味着短路
- 如果x > 200,意味着不短路
- 如果x<= 200,意味着短路
# 命令执行验证:

生成中间代码
clang -S -emit-llvm if-boolexpr.c -o if-boolexpr-opt0.ll
生成dot文件
opt -dot-cfg if-boolexpr-opt0.ll
让dot文件画图
dot -Tpdf .main.dot -o if-boolexpr-opt0-cfg.pdf

# ANTLR实现
CodeGenListener.java
package codegen;
import org.antlr.v4.runtime.tree.ParseTreeProperty;
import java.io.FileWriter;
import java.io.IOException;
public class CodeGenListener extends ControlBaseListener {
private final ParseTreeProperty<String> trueLabel = new ParseTreeProperty<>();
private final ParseTreeProperty<String> falseLabel = new ParseTreeProperty<>();
private final ParseTreeProperty<String> nextLabel = new ParseTreeProperty<>();
private final ParseTreeProperty<String> beginLabel = new ParseTreeProperty<>();
private final ParseTreeProperty<String> codeProperty = new ParseTreeProperty<>();
private FileWriter fileWriter;
private int labelCounter = 1;
public CodeGenListener(String file) throws IOException {
fileWriter = new FileWriter(file);
}
@Override
public void enterProg(ControlParser.ProgContext ctx) {
nextLabel.put(ctx.stat(), getNewLabel());
}
@Override
public void exitProg(ControlParser.ProgContext ctx) {
String code = String.format("%s%n%s:",
codeProperty.get(ctx.stat()),
nextLabel.get(ctx.stat()));
codeProperty.put(ctx, code);
dump(codeProperty.get(ctx));
}
@Override
public void exitAssignStat(ControlParser.AssignStatContext ctx) {
codeProperty.put(ctx, "ASSIGN");
}
@Override
public void enterWhileStat(ControlParser.WhileStatContext ctx) {
beginLabel.put(ctx, getNewLabel() + "begin");
trueLabel.put(ctx.bool(), getNewLabel());
falseLabel.put(ctx.bool(), nextLabel.get(ctx));
nextLabel.put(ctx.stat(), beginLabel.get(ctx));
}
@Override
public void exitWhileStat(ControlParser.WhileStatContext ctx) {
String code = String.format("%s:%n%s%n%s:%n%s%n%s",
//对着规则一行一行翻译
beginLabel.get(ctx),
codeProperty.get(ctx.bool()),
trueLabel.get(ctx.bool()),
codeProperty.get(ctx.stat()),
"goto " + beginLabel.get(ctx));
codeProperty.put(ctx, code);
}
@Override
public void enterIfStat(ControlParser.IfStatContext ctx) {
trueLabel.put(ctx.bool(), getNewLabel());
falseLabel.put(ctx.bool(), nextLabel.get(ctx));
nextLabel.put(ctx.stat(), nextLabel.get(ctx));
}
@Override
public void exitIfStat(ControlParser.IfStatContext ctx) {
String code = String.format("%s%n%s:%n%s",
codeProperty.get(ctx.bool()),
trueLabel.get(ctx.bool()),
codeProperty.get(ctx.stat()));
codeProperty.put(ctx, code);
}
@Override
public void enterAndExpr(ControlParser.AndExprContext ctx) {
trueLabel.put(ctx.lhs, getNewLabel());
falseLabel.put(ctx.lhs, falseLabel.get(ctx));
trueLabel.put(ctx.rhs, trueLabel.get(ctx));
falseLabel.put(ctx.rhs, falseLabel.get(ctx));
}
@Override
public void exitAndExpr(ControlParser.AndExprContext ctx) {
String code = String.format("%s%n%s:%n%s",
codeProperty.get(ctx.lhs),
trueLabel.get(ctx.lhs),
codeProperty.get(ctx.rhs));
codeProperty.put(ctx, code);
}
@Override
public void exitOrExpr(ControlParser.OrExprContext ctx) {
String code = String.format("%s%n%s:%n%s",
codeProperty.get(ctx.lhs),
falseLabel.get(ctx.lhs),
codeProperty.get(ctx.rhs));
codeProperty.put(ctx, code);
}
@Override
public void enterOrExpr(ControlParser.OrExprContext ctx) {
trueLabel.put(ctx.lhs, trueLabel.get(ctx));
falseLabel.put(ctx.lhs, getNewLabel());
trueLabel.put(ctx.rhs, trueLabel.get(ctx));
falseLabel.put(ctx.rhs, falseLabel.get(ctx));
}
@Override
public void exitRelExpr(ControlParser.RelExprContext ctx) {
String code = String.format("if %s goto %s%ngoto %s",
ctx.getText(),
trueLabel.get(ctx),
falseLabel.get(ctx));
codeProperty.put(ctx, code);
}
@Override
public void exitTrueExpr(ControlParser.TrueExprContext ctx) {
codeProperty.put(ctx, "goto " + trueLabel.get(ctx));
}
@Override
public void exitFalseExpr(ControlParser.FalseExprContext ctx) {
codeProperty.put(ctx, "goto " + falseLabel.get(ctx));
}
private void dump(String code) {
try {
fileWriter.write(code);
fileWriter.close();
} catch (IOException ioe) {
System.err.println(ioe.getMessage() + " : " + code);
}
}
private String getNewLabel() {
return "L" + labelCounter++;
}
}
死循环

# 布尔表达式的作用

