前面已經介紹了全域性函式和全域性變數的宣告處理,但全域性變數的初始化,還沒有詳細地分析,現在就來幹這件事情。比如編寫
c的程式,有如下的**:
#001
#002 int g_ntest = 100;
#003
#004 int main(void)
#005
#014 else if (t == '=')
#015
#023 }
#024 else if (p->sclass == static && !isfunc(p->type)
#025 && p->type->size == 0)
#026
#030 在第
14行裡,就會把
g_ntest
變數後面的等號識別出來,然後就進入處理後面常量表示式的流程了。也就是呼叫函式
initglobal
來處理常量表示式的一大堆的工作,比如常量的計算,常量的型別,常量的儲存位置等等。
initglobal
函式如下:
#001 //
初始化全域性變數.
#002 static void initglobal(symbol p, int flag)
#003
#015 else
#016
#020
#021 if (t == '=')
#022
#025
#026 //
常量初始化處理.
#027 ty = initializer(p->type, 0);
#028
#029
#030 if (isarray(p->type) && p->type->size == 0)
#031
#034
#035 if (p->sclass == extern)
#036
#039
#040 }
#041 }
在初始化
initglobal
函式裡,呼叫函式
defglobal
來儲存這個全域性變數符號到彙編不同的段裡,比如在資料段,還是在常量段。最後呼叫函式
initializer
來處理常量表示式,當然常量的值也需要儲存到資料區的。 函式
initializer
是用來處理常量表示式的,它的**如下:
#001 /*
常量表示式的處理
- constexpr | */
#002 type initializer(type ty, int lev)
#003 ;
#008
#009 ty = unqual(ty);
#010 if (isscalar(ty))
#011
#023 else
#024
#028
#029 //
返回基本型別的表示式樹.
#030 e = pointer(e);
#031
#032 //
根據左邊型別和右邊的型別來選擇合適的返回型別.
#033 if ((aty = assign(ty, e)) != null)
#034
#038 else
#039
#043
#044 //
根據常量表示式生成**.
#045 n = genconst(e, 1);
#046
#047
#048 deallocate(stmt);
#049 needconst--;
#050 }
#051
#052 if ((isunion(ty) || isstruct(ty)) && ty->size == 0)
#053 ;
#056 error("cannot initialize undefined `%t'/n", ty);
#057 skipto(';', follow);
#058 return ty;
#059 }
#060 else if (isunion(ty))
#061
#069 else
#070
#076 }
#077 else if (isstruct(ty))
#078 ', follow);
#085 }
#086 else if (lev > 0)
#087
#090 else
#091
#095 }
#096
#097 if (isarray(ty))
#098
#101
#102 if (isarray(ty) && ischar(aty))
#103
#113 else if (t == '
#122
#123 n = initchar(0, aty);
#124 test('}', follow);
#125 }
#126 else if (lev > 0 && ty->size > 0)
#127 n = initchar(ty->size, aty);
#128 else
#129
#133 }
#134 else if (isarray(ty))
#135
#151
#152 t = ccaicompiler::instance()->getlex()->gettoken();
#153 }
#154 else if (t == '
#163
#164 n = initarray(0, aty, lev + 1);
#165 test('}', follow);
#166 }
#167 else if (lev > 0 && ty->size > 0)
#168 n = initarray(ty->size, aty, lev + 1);
#169 else
#170
#174 }
#175
#176 //
#177 if (ty->size)
#178
#185 else if (isarray(ty) && ty->ptype->size > 0)
#186 ty = array(ty->ptype, n/ty->ptype->size, 0);
#187 else
#188
#191
#192 //
返回型別.
#193 return ty;
#194 }
通過呼叫表示式處理函式
expr1
來計算常量的值,然後呼叫後端介面
genconst
來生成儲存常量的**,並且設定變數
g_ntest
的初始化為常量表示式的值。這樣就把全域性變數初始化的**分析完成。
LCC編譯器的源程式分析 12 13
語法分析是比較複雜的處理,下面再來分析乙個例子,它的 如下 typedef unsigned short wchar t typedef wchar t wint t 第一句語句在lcc裡的處理,前面已經解釋清楚,主要生成wchar t儲存符號表裡,並且記錄這個id的型別屬性。那麼第二句是怎麼樣通過...
LCC編譯器的源程式分析 18 19
lcc編譯器的源程式分析 19 全域性函式的定義 函式定義funcdefn處理裡,已經準備好呼叫引數和引數返回,接著就是呼叫全域性函式宣告來處理。如下面的 132 宣告函式。133 cfunc dclglobal sclass,id,ty,pt 134 上面的 是處理函式全域性定義。現在就去就分析d...
LCC編譯器的源程式分析 20 復合語句
在 c語言裡,有一種語句叫做復合語句。它是由 把一些語句括起來的,如下面的例子 在lcc 裡處理這樣的復合語句的函式是 compound 它在上面函式定義函式 funcdefn 是這樣呼叫的 150labels table null,labels 151stmtlabs table null,lab...