zoukankan      html  css  js  c++  java
  • 现代编译原理——第五章:活动记录

      转自: http://www.cnblogs.com/BlackWalnut/p/4559245.html

          第五章是到目前位置最让我头疼的一章,不是因为难,是因为对最终的目的不太明确。整章前半部分用十分精简的语言介绍了一个新的概念,活动记录,也就是在函数调用时,一个调用栈究竟发生了什么事。但是,在最终编码实现过程中,总不能理解作者为什么给了这些变量?或者说,完全不知道作者究竟想让我完成一个怎样的功能。纠结了好几天,后来索性往后继续看,看看能不能找到其他的线索。直到看完后一章,硬着头皮写了一半的时候,才豁然开朗。原来作者是这个意图!所以,如果你也不知道这章程序最终要得到一个什么样的结果,建议把后面一章也读了,因为这两章讲的是同一个东西的不同部分。

      先看看一些理论知识吧。首先,这个活动记录,就是我们通常意义上的函数调用堆栈,所以又叫栈帧。是内存中的一个区域,在这个区域中包含了一个函数中所有参数,局部变量,临时变量,返回值等信息,如果这种语言还允许嵌套的函数声明,那么,还要有一个叫做静态链的东西。这些东西在不同的目标机器上对应的布局是不一样的,书上介绍了一种标准布局。

      那么,一个函数怎么去访问他自己的变量呢?用的是(栈指针+偏移量),因为对cpu而言,加法运算是比较简单的,所以,在实际中,栈指针是位于低地址,表示栈的下界,而帧指针位于高地址,表示栈的上界。这样就会发现,其实,栈顶的地址要比栈底的地址低。

      其实并不是所有参数都要放入栈(内存)中的,有些变量可以放入寄存器中,这样可以省去很多的访存时间。但是,一个程序可以有多个函数,寄存器的个数却是有限。那么,当一个函数调用另一个函数,且都要使用同一个寄存器的时候,谁去将原来的寄存器中的内容的保存起来呢?如果是调用其他函数的函数负责,则成为调用者保护,如果是被调用函数负责,那么就是被调用者保护。

        通常情况下,我们会将传入一个函数的参数放入寄存器中,但是,寄存器的数量是有限,放不下的怎么办?例如,对于f(n1 , n2 , ...,nx)的函数,我们会将前k个,假如k为4,放入寄存器中,剩下的x-k个我们就放入调用函数f的函数的栈帧的末尾,紧邻着栈指针,这x-k个区域就称为传出参数。但是这x-k块区域对于被调用函数f来说就被称为传入参数。思考一下,如果f又去调用了其他函数呢?那么那k个参数就要被移出寄存器,放到f中称为局部变量的区域中,这块区域是紧挨着传出参数(传入参数,对函数f而言)。

      那么,除了以上参数传递过程中有变量要被移出寄存器,还有其他一些情况需要将寄存器中的参数放到内存中。比如,在一个函数定义中取了一个外部函数中的一个变量的地址(此时要求语言支持函数内部定义新的函数),那么这个变量就要写回内存,要不然,你取到的地址是寄存器地址,如果在以后的处理过程中这个变量被移出了寄存器,岂不是就找不到了么。

      当然,还有很多情况需要考虑,这里就不一一列举了,虎书上已经讲的很明白了,并且,对于所有本来在寄存器中,后来被移动内存中的变量称为逃逸。那么,如何在一个函数内部取用外部函数的变量呢?这就要用一个称为静态来链的东西,这个东西就是能让你在一个函数内部顺藤摸瓜的找到你需要的变量,类似于一个链表。

      好了,说了这么多,我们来看看最后的实现吧。本章要实现的,其实就是这个栈。在前几次的数据结构中保留了一个称为scape的区域没有用,这是个bool变量,使用这个变量来标记tiger中一个变量是不是逃逸的。如何计算一个变量是不是逃逸的呢?因为这些逃逸信息只有在完成这个程序扫描后才能知道。所以,对得到的抽象语法树进行两次扫描,第一次得到变量的逃逸信息,第二次才是对对语法树进行类型检测,同时生成栈帧。

      我的代码并没有实现对抽象语法的逃逸变量检测,我默认所有的变量都是可以逃逸的。所以本次代码的主要部分就是frame.h以及frame.cpp,并且不涉及到对这frame.h中函数的真正使用。对其使用的部分将在下一章中体现。以下是源码:

      

    复制代码
    #ifndef FRAME_H_
    #define FRAME_H_
    #include "temp.h"
    #include "util.h"
    #include "tree.h"
    
    const int F_wordSize = 4 ;
    typedef struct F_frame_ *F_frame ;
    typedef struct F_access_ *F_access ;
    typedef struct F_accesslist_ *F_accesslist ;
    struct F_accesslist_ { F_access head; F_accesslist tail; };
    typedef struct F_frag_ *  F_frag ;
    typedef struct F_fragList_ * F_fragList ;
    
    
    struct F_frame_ { 
                     Temp_label name ; 
                     int framesize ;
                     F_accesslist formals; 
                     F_accesslist locals; 
                     };
    struct F_access_ {
                      enum { inFrame , inReg } kind  ;
                      union{
                          int offset ;
                          Temp_temp reg ;
                           } u ;
                      };
    struct F_frag_ {
                    enum { F_stringFrag , F_procFrag } kind ;
                    union {
                        struct { 
                                 Temp_label label ;
                                 string str ; 
                               } stringg ;
                        struct {
                                 T_stm body ;
                                 F_frame frame ;
                                } proc ;
                            }u ;
                    };
    struct F_fragList_{  F_frag head ; F_fragList tail; };
    
    F_frag F_StringFrag( Temp_label label , string str) ;
    F_frag F_ProcFrag ( T_stm stm , F_frame frame ) ;
    
    F_fragList F_FragList(F_frag frag , F_fragList tail) ;
    
    
    Temp_temp F_FP(void);   
    Temp_temp F_RV(void) ;  
    
    
    
    F_frame F_newframe(Temp_label name , U_boolList formals) ;
    F_accesslist F_Accesslist(F_access head , F_accesslist tail) ;
    
    
    Temp_label F_name(F_frame f) ;
    F_accesslist F_formals(F_frame f) ;
    F_access F_allocLoacl(F_frame f  , bool escape );
    
    F_access InFrame(int offset) ;
    F_access InReg(Temp_temp reg) ;
    
    T_exp F_Exp(F_access acc, T_exp framePtr);
    T_exp F_externalCall(string s , T_expList explist);
    
    T_stm F_procEntryExit1(F_frame frame , T_stm stm) ;
    #endif
    复制代码
    复制代码
    #include "frame.h"
    #include "tree.h"
    const int offset = -4 ;
    
    
    static Temp_temp fp = NULL;
    Temp_temp F_FP()
    {
        if(fp==NULL)
        {
            fp = Temp_newtemp();
            
        }
        return fp;
    }
    static Temp_temp rv = NULL ;
    Temp_temp F_RV()
    {
        if (rv == NULL )
        {
            rv = Temp_newtemp() ;
        }
        return rv ;
    }
    F_access F_allocLoacl(F_frame f , bool escape )
    {
        F_access access ;
        if (escape == true)
        {
            access = InFrame(f->framesize) ;
            f->framesize -= offset;
        }
        else
        {
            access = InReg(Temp_newtemp()) ;
        }
        f->locals = F_Accesslist(access , f->locals) ;
        return access ;
    }
    
    F_access InFrame(int offset)
    {
        F_access tmp = (F_access) checked_malloc(sizeof(*tmp)) ;
        tmp->kind = F_access_::inFrame ;
        tmp->u.offset = offset ;
        return tmp ;
    }
    
    F_access InReg(Temp_temp reg)
    {
        F_access tmp = (F_access) checked_malloc(sizeof(*tmp)) ;
        tmp->kind = F_access_::inReg ;
        tmp->u.reg = reg ;
        return tmp ;
    }
    
    F_frame F_newframe(Temp_label name , U_boolList formals)
    {
        F_frame frame =(F_frame) checked_malloc(sizeof(*frame)) ;
        frame->name = name ;
        frame->formals = NULL ;
        U_boolList par = formals ;
        F_access acc ;
        frame->framesize = 0 ;
        while(par != NULL)
        {
            if (par->head)
            {
              acc = InFrame(frame->framesize) ;   
              frame->framesize -= offset ;
            }
            else
            {
             acc = InReg(Temp_newtemp()) ;
            }
            frame->formals = F_Accesslist(acc , frame->formals) ;
            par = par->tail ;
        }
       frame->locals = NULL ;
       return frame ;
    }
    
    F_accesslist F_Accesslist(F_access head , F_accesslist tail)
    {
        F_accesslist tmp = (F_accesslist)checked_malloc(sizeof(*tmp)) ;
        tmp->head = head ;
        tmp->tail = tail ;
        return tmp ;
    }
    
    T_exp F_Exp(F_access acc, T_exp framePtr)
    {
        if (acc->kind == F_access_::inFrame )
        {
            return T_Mem(T_Binop(T_plus, framePtr, T_Const(acc->u.offset)));
        }
        return  T_Temp(acc->u.reg);
    }
    
    F_frag F_StringFrag(Temp_label label , string str)
    {
        F_frag tmp = (F_frag) checked_malloc(sizeof(*tmp)) ;
        tmp->kind = F_frag_::F_stringFrag ;
        tmp->u.stringg.label = label ;
        tmp->u.stringg.str = str ;
        return tmp ;
    }
    
    F_frag F_ProcFrag( T_stm stm , F_frame frame )
    {
        F_frag tmp = (F_frag) checked_malloc(sizeof(*tmp)) ;
        tmp->kind = F_frag_::F_procFrag ;
        tmp->u.proc.body = stm ;
        tmp->u.proc.frame = frame ;
        return tmp ;
    }
    
    F_fragList F_FragList(F_frag frag , F_fragList tail)
    {
        F_fragList tmp = (F_fragList) checked_malloc(sizeof(*tmp)) ;
        tmp->head = frag ;
        tmp->tail = tail ;
        return tmp; 
    }
    T_stm F_procEntryExit1(F_frame frame , T_stm stm) 
    {
        return stm ;
    }
    
    
    F_accesslist F_formals(F_frame frame)
    {
        return frame->formals;
    }
    复制代码
  • 相关阅读:
    [原]关于在Python和C#之间消息传递的问题
    【原】为DevExpress的ChartControl添加Y轴控制 和 GridControl中指定列添加超级链接
    【原】使用Json作为Python和C#混合编程时对象转换的中间文件
    【原】在Matplotlib绘图中添加Latex风格公式
    【原】关于AdaBoost的一些再思考
    【原】使用Tkinter绘制GUI并结合Matplotlib实现交互式绘图
    使用C#+Linq+SQL快速开发业务
    oracle expdp导出时报 ora-39070:无法打开日志文件
    Oracle 关于expdp和impdp的应用实践
    IIS7启动优化
  • 原文地址:https://www.cnblogs.com/jacksplwxy/p/10052781.html
Copyright © 2011-2022 走看看