區域性變數的處理是比較特別,它是複雜語句裡面宣告,作用域也只限於復合語句裡。如下面的例子:
上面的a
就是區域性變數的宣告。
現在再來仔細地分析
compound
裡處理區域性變數的**。如下:
#031//
區域性變數宣告處理.
#032while (kind[t] == char || kind[t] == static
#033 || istypename(t, tsym) && getchr() != ':')
#034
上面呼叫函式
decl
來處理宣告,跟前面介紹過的宣告是一樣的。只有乙個地方不同,它是呼叫函式
dcllocal
來分析區域性變數的。下面再來回顧一下
decl
函式:
#001static void decl(symbol (*dcl)(int, char *, type, coordinate *))
#002
#048 else
#049
在以前處理的變數宣告全是全域性變數,因此不會執行到第
50行的**。 …
#076 else
#077 在第
78行裡是呼叫區域性變數宣告函式
dcllocal
來分析區域性變數。
那麼區域性變數函式又是怎麼樣處理區域性變數的呢?前面已經分析了全域性變數,引數變數,現在就來分析
dcllocal
的**,如下:
#001//
區域性變數宣告.
#002static symbol dcllocal(int sclass, char *id, type ty, coordinate *pos)
#003
#014else if (sclass == register
#015 && (isvolatile(ty) || isstruct(ty) || isarray(ty)))
#016
#021 第
6行到第
20行處理區域性變數的儲存型別。
#022//
查詢是否已經宣告。
#023q = lookup(id, identifiers);
#024if (q && q->scope >= level
#025 ||q && q->scope == param && level == local)
#026 if (sclass == extern && q->sclass == extern
#027 && eqtype(q->type, ty, 1))
#028 ty = compose(ty, q->type);
#029 else
#030 error("redeclaration of `%s' previously declared at %w/n", q->name, &q->src);
#031 第
23行是查詢區域性變數是否已經宣告過。 在第
24行是判斷這個型別是否復合型別,如果不是就會出錯處理;如果是的話,就進行復合型別處理。
#032//
儲存到區域性變數表。
#033assert(level >= local);
#034p = install(id, &identifiers, level,
#035 sclass == static || sclass == extern ? perm : func);
#036p->type = ty;
#037p->sclass = sclass;
#038p->src = *pos;
#039 第
34行是儲存區域性變數到
identifiers
符號表。 第
36行到第
38行儲存區域性變數的屬性。
#040switch (sclass)
#041
#055 }
#056
#057 if (!eqtype(p->type, q->type, 1))
#058 warning("declaration of `%s' does not match previous declaration at %w/n", q->name, &q->src);
#059
#060 p->u.alias = q;
#061 break; 第
42行處理宣告為外面定義的區域性變數處理。
#062case static:
#063 (*ir->defsymbol)(p);
#064 initglobal(p, 0);
#065 if (!p->defined)
#066 if (p->type->size > 0)
#067
#071 else
#072 error("undefined size for `%t %s'/n",
#073 p->type, p->name);
#074 p->defined = 1;
#075 break;
上面的**是處理靜態區域性變數。
#076case register:
#078 regcount++;
#079 p->defined = 1;
#080 break;
上面的**是處理暫存器型別的區域性變數,新增到
registers
列表。
#081case auto:
#083 p->defined = 1;
#084 if (isarray(ty))
#085 p->addressed = 1;
#086
#087 break;
上面的**是處理一般最常用的
auto
型別區域性變數,並且新增到
autos
列表。
#088default: assert(0);
#089}
#090
#091
下面的**開始處理區域性變數定義時的初始化行為。
#092//
區域性變數的初始化處理。
#093if (t == '=')
#094');
#110 }
#111 else
#112 e = expr1(0); 第
102行是判斷簡單型別的初始化,還是陣列的初始化。 第
105行到第
110行是處理結構的初始化。 第
112行是處理簡單的表示式初始化。表示式函式
expr1
是乙個複雜的處理函式,後面再仔細地分析它的實現。
#113 }
#114 else
#115
#131 第
115行到
130行是處理陣列的初始化。
#132 walk(root(asgn(p, e)), 0, 0);
#133 p->ref = 1;
#134}
#135 第
132行是先呼叫函式
asgn
生成賦值語法樹,並且作為中間表示。接著呼叫函式
walk
去遍歷整個賦值樹,進行
dag處理,刪除一些公共表示式。後面再細述這些處理。
#136if (!isfunc(p->type) && p->defined && p->type->size <= 0)
#137 error("undefined size for `%t %s'/n", p->type, id);
#138
#139return p;
#140} 第
136行是處理區域性變數型別出錯。 在第
139行裡返回這個區域性變數的符號表示。
像第一節裡的例子:
int ntest1 = 1;
int ntest2 = 2;
int ntest3;
int i;
上面這些區域性變數都是通過上面的函式來處理完成的。
dcllocal
函式主要分析了區域性變數是否合法,然後新增到合適的區域性變數列表裡,最後分析區域性變數的初始化賦值。
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編譯器的源程式分析 21 區域性變數的宣告
區域性變數的處理是比較特別,它是複雜語句裡面宣告,作用域也只限於復合語句裡。如下面的例子 上面的a 就是區域性變數的宣告。現在再來仔細地分析 compound 裡處理區域性變數的 如下 031 區域性變數宣告處理.032 while kind t char kind t static 033 ist...