主旨就是往x86汇编上靠
实验思路
依然是在遍历抽象语法树的时候生成中间代码。
因为四元式形式和 x86 汇编形式相差较多,为了相对简便的进行目标代码生成,因此中间代码构造时选择与 x86 汇编相近的形式。并且尽量使用伪指令,减少对代码的翻译。
四元式定义
采用(operator,operand1,operand2,result)的基本形式。对于程序控制流的if 等语句,不使用断点和jmp。
声明并归置临时变量
在中间代码生成中使用的局部变量,必须在过程开始的时刻定义,因此需要在使用临时 变量时,将声明加入四元式中,并且在 visitor 遍历语法树时生成的局部变量放到当前临时变 量过程声明的下方,如下图所示。
对 ICPrinter 进行打印顺序的改写,对一个函数首先打印参数四元式 (param,NULL,NULL,NULL)和局部变量定义四元式(var,NULL,NULL,NULL)部分,让局部变量的定义紧跟函数声明,最终在中间代码生成这样的格式。
数组的值访问和下标访问
当数组在赋值语句右边时,需要知道ArrayAccess本身的值,但是如果在数组在左边,那么我们需要知道它的下标或者偏移量。
如代码中:A[i] = A[i + 1]
,对于右边我们想知道A[i + 1]是多少,但是左边我们想知道i是多少。
目标代码生成
由于四元式在经过重排顺序后已经是正确汇编控制流代码了,在目标代码生成中,只需将每行的四元式翻译成对应的汇编代码即可。
- 全局整形变量, 判断当前变量是否有初始值,如果下一个 Quat 的操作符 是’= ’,那么当前变量有初始值,否则没有初始化为 0。
有初值:(var,int,NULL,x) (=,1,NULL,x) -> x DWORD 1
无初值:(var,int,NULL,x) -> x DWORD 0 - 字符串变量,需要去掉在字符串中显式定义的’\n ’,然后在字符串末 尾添加 0ah 作为换行符,否则会在运行时错误的输出不能解析的\n 换行符。也 要注意对仅为换行符的字符串的替换,不定义空字符串。
有内容: (var,”string\n”,NULL,String1) ->
String1 db“stirng”,0ah,0
仅为换行符: (var,”\n”,NULL,String2) ->
String2 db 0ah,0 - 数组声明 首先计算数组限定长度,因为 int 占 4 个字节,因此算出数组长度后×4 获 得数组大小。
(array,int,[5, 5],A) -> A 100 DWORD DUP(0) - 函数声明 需要在函数入口处声明参数,再检索到 FUNC_BEGIN 的四元式后, 向下检索连续的 param 的四元式,那么这些就是当前过程的参数列表。
(FUNC_BEGIN,int,NULL,func)
(param,int,NULL,x)
-> func PROC x :DWORD - 局部变量定义,在相同的声明函数下,需要打上 local 标签,并且汇编代码 有不同的声明形式。
(var,int,NULL,x) -> local x :DWORD
(array,int,[5, 5],A) -> local A[100]:DWORD - 调用函数,先把当前参数栈内的所有参数取出,然后附加到 Invoke 伪指 令后面,通过 invoke 伪指令调用子过程。
(arg,NULL,NULL,23) (invoke,f,NULL,t1) -> invoke f,23 - 四则运算示例
- 控制流 所有控制流和逻辑表达式都使用伪指令解决,能省则省。
代码:
ExampleICprinter:
package bit.minisys.minicc.icgen;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import bit.minisys.minicc.parser.ast.*;
public class ExampleICPrinter {
private List<Quat> quats;
private HashSet<String> nameSpace;
public ExampleICPrinter(List<Quat> quats) {
this.quats = quats;
}
public void print(String filename) {
nameSpace = new HashSet<>();
StringBuilder sb = new StringBuilder();
for (int i = 0;i < quats.size();++i) {
Quat quat = quats.get(i);
String op = quat.getOp();
String res = astStr(quat.getRes());
String opnd1 = astStr(quat.getOpnd1());
String opnd2 = astStr(quat.getOpnd2());
if(op.equals("FUNC_BEGIN")) {
nameSpace.clear();
sb.append("("+op+","+ opnd1+","+opnd2 +"," + res+")\n");
//打印Var 和 param
for(int j = i + 1;j < quats.size();++j) {
Quat quat1 = quats.get(j);
String op1 = quat1.getOp();
String res1 = astStr(quat1.getRes());
String opnd11 = astStr(quat1.getOpnd1());
String opnd21 = astStr(quat1.getOpnd2());
if(op1.equals("var") && !nameSpace.contains(res1)) {
sb.append("(" + op1 + "," + opnd11 + "," + opnd21 + "," + res1 + ")\n");
nameSpace.add(res1);
} else if(op1.equals("param")) {
sb.append("(" + op1 + "," + opnd11 + "," + opnd21 + "," + res1 + ")\n");
}
if(op1.equals("FUNC_END")) {
break;
}
}
//打印非Var
for(int j = i + 1;j < quats.size();++j) {
Quat quat1 = quats.get(j);
String op1 = quat1.getOp();
String res1 = astStr(quat1.getRes());
String opnd11 = astStr(quat1.getOpnd1());
String opnd21 = astStr(quat1.getOpnd2());
if(!op1.equals("var") && !op1.equals("param")) {
sb.append("(" + op1 + "," + opnd11 + "," + opnd21 + "," + res1 + ")\n");
}
if(op1.equals("FUNC_END")) {
i = j;
break;
}
}
}
else sb.append("("+op+","+ opnd1+","+opnd2 +"," + res+")\n");
}
// write
try {
FileWriter fileWriter = new FileWriter(new File(filename));
fileWriter.write(sb.toString());
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private String astStr(ASTNode node) {
if (node == null) {
return "";
}else if (node instanceof ASTIdentifier) {
return ((ASTIdentifier)node).value;
}else if (node instanceof TemporaryValue) {
return ((TemporaryValue)node).name();
}else if (node instanceof DescribeNode){
return node.getType();
} else if (node instanceof ASTVariableDeclarator) {
return ((ASTVariableDeclarator) node).getName();
} else if (node instanceof ASTIntegerConstant) {
return ((ASTIntegerConstant)node).value.toString();
} else if (node instanceof ASTStringConstant) {
return ((ASTStringConstant)node).value;
} else {
return "";
}
}
}
ExampleIBuilder:
package bit.minisys.minicc.icgen;
import java.util.*;
import bit.minisys.minicc.parser.ast.*;
import bit.minisys.minicc.pp.internal.D;
import bit.minisys.minicc.pp.internal.I;
import bit.minisys.minicc.pp.internal.Q;
import bit.minisys.minicc.pp.internal.X;
import bit.minisys.minicc.semantic.XYSymbolTable;
import org.python.antlr.op.In;
public class ExampleICBuilder implements ASTVisitor{
private XYSymbolTable globalTable;
private XYSymbolTable localTable;
private String declarationType;
private String identifierOfArray;
private Map<ASTNode, ASTNode> map;
private List<Quat> quats;
private int tmpId,StringId;
private LinkedList <String> equalOps;
public ExampleICBuilder() {
globalTable = new XYSymbolTable();
map = new HashMap<ASTNode, ASTNode>();
localTable = globalTable;
quats = new LinkedList<>();
tmpId = 0;
StringId = 0;
equalOps = new LinkedList<>();
equalOps.add("+="); equalOps.add("-="); equalOps.add("#="); equalOps.add("/=");
equalOps.add("%="); equalOps.add("&="); equalOps.add("|="); equalOps.add(">>=");
equalOps.add("<<=");
}
public List<Quat> getQuats() {
return quats;
}
private String getType(List<ASTToken> specifiers) {
StringBuilder type = new StringBuilder();
if( specifiers != null ){
for (ASTToken specifier : specifiers) {
type.append(specifier.value);
}
}
return type.toString();
}
//第一步进入CU
@Override
public void visit(ASTCompilationUnit program) throws Exception {
program.scope = localTable;
for (ASTNode node : program.items) {
if(node instanceof ASTFunctionDefine) {
visit((ASTFunctionDefine) node);
}else if(node instanceof ASTDeclaration) {
visit((ASTDeclaration)node);
}
}
}
//一个声明语句 (array, int , x , [3,2])
@Override