本书的三个难点:
1.Expr:表达式的编译:如:int i = 1*2+3*4;
对应的汇编代码如下:
.file "zhong.cb"
.text
.globl main
.type main,@function
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $3, %eax
imull $4, %eax
movl %eax, -8(%ebp) //相当于push
movl $1, %eax
imull $2, %eax
movl -8(%ebp), %ecx //相当于pop
addl %ecx, %eax
movl %eax, -4(%ebp)
.L0:
movl %ebp, %esp
popl %ebp
ret
.size main,.-main
解决方法,把中间变量保存在栈里面:把1*2的结果push进栈,然后编译3*4,此时%eax已经空出来了,再将1*2的结果pop出栈。
2.LocalVar:变量作用域的消解
比如:
int i;
int main(){
int j = 0;
if(j){
int k = 0;
}
}
编译时如何确定i,j, k的作用域?
解决方法:用了一个树形结构Scope保存变量的作用域,为什么不直接用HashMap,保存然后在每个blockNode里。因为作用域是层层递进的,用HashMap无法表达这种关系。比如在for循环里面用了函数体的局部变量i,在for循环的block里并没有定义i,因此在for循环的block中的hashmap找不到定义,需要向上查找。
3.Scope树的具体实现
问题引入:
int fun(int i, int j){
int m = 0;
j = j + 1;
if(i > 0){
int y = 0;
m++;
}
}
编译if节点中的block中的m++;时如何找到m的作用域的?
类Scope中有child和parent属性,方便查找上一级作用域Scope,当编译fun节点时将fun的参数和局部变量的Scope压入栈,编译if节点时将if节点的block的作用域Scope压入栈,压入栈的同时设置if的scope的parent为fun,fun的scope的child为if,这一组操作封装在一个函数中:
private void pushScope(List<? extends DefinedVariable> vars) {
LocalScope scope = new LocalScope(currentScope());
for (DefinedVariable var : vars) {
if (scope.isDefinedLocally(var.name())) {
error(var.location(),
"duplicated variable in scope: " + var.name());
}
else {
scope.defineVariable(var);
}
}
scopeStack.addLast(scope);
}
public LocalScope(Scope parent) {
super();
this.parent = parent;
parent.addChild(this);
variables = new LinkedHashMap<String, DefinedVariable>();
}