(轉載請表明出處 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; }