《自制编译器》:变量作用域——Scope实现

本书的三个难点:

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>();

    }





 

 

猜你喜欢

转载自blog.csdn.net/raylrnd/article/details/82633268