LCC編譯器的源程式分析 21 區域性變數的宣告

2021-08-22 09:09:09 字數 4077 閱讀 2901

區域性變數的處理是比較特別,它是複雜語句裡面宣告,作用域也只限於復合語句裡。如下面的例子:

上面的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...