LCC編譯器的源程式分析 12 13

2021-04-13 01:15:19 字數 3532 閱讀 7560

************************************/

語法分析是比較複雜的處理,下面再來分析乙個例子,它的**如下:

typedef unsigned short wchar_t;

typedef wchar_t wint_t;

第一句語句在lcc裡的處理,前面已經解釋清楚,主要生成wchar_t儲存符號表裡,並且記錄這個id的型別屬性。

那麼第二句是怎麼樣通過上面的函式來分析的呢?接下來就去分析c編譯器怎麼處理它。

與第一句語句一樣,先識別typedef出來,接著就調函式decl(dclglobal),然後呼叫函式specifier來處理。在函式specifier裡:

#001 //說明

#002 static type specifier(int *sclass)

#003

#101               assert(cp == rcp);

#102               token = (char *)rcp - 1;

#103               while (map[*rcp]&(digit|letter))

#104                    rcp++;

#105               token = stringn(token, (char *)rcp - token);

#106               tsym = lookup(token, identifiers);

#107               cp = rcp;

#108               return id;

在第96行到第99行是重新填充字元緩衝區,以便識別完整的變數id出來。

在第102行到第105行裡,就獲取id的字串,並儲存到token裡。

在第106行裡查詢這個id是否已經宣告,如果沒有宣告返回是空指令給tsym。

在第108行裡返回id這個記號來標識當前已經識別出乙個id了。

再仔細地看一下第106行,它通過函式lookup到符號表identifiers查詢當前的id是否已經宣告,如果已經宣告就返回給tsym儲存。由於語句(typedef wchar_t wint_t;

)中的wchar_t在前面已經宣告,那麼這裡的tsym肯定就是返回它了,這樣就得到了wchar_t的型別屬性了。有了型別屬性,在函式specifier的處理**如下:

#079         case id:

#080               if (istypename(t, tsym) && type == 0

#081                    && sign == 0 && size == 0)

#082              

#098

#099                    p = &type;

#100                    t = gettok();

#101               }

#102               else

#103                  

#106               break;

由於在詞法分析函式gettok()獲取到了tsym,也就是已經宣告的型別wchar_t,所以在第80行和第81行判斷它是型別,而不是變數id了,就進入第83行裡面處理,並在第84行儲存當前的型別ty,也就是wchar_t宣告的型別。再獲取下乙個記號,它是wint_t,接著的處理就跟其它宣告處理是一樣的了,在specifier返回型別,在decl函式裡儲存到符號表identifiers。

現在再來總結一下處理語句(typedef wchar_t wint_t;),先識別typedef,接著通過詞法分析裡查詢符號表可以知道wchar_t已經宣告為型別,接著就可以儲存wint_t到符號表,它的型別就是wchar_t所宣告的型別

lcc編譯器的源程式分析(13)指標型別的宣告

在c語言裡,指標是最靈活的資料型別,它具有低階語言的特點,高效快速,不過學會它就不是那麼容易了。由於指標是直接面向機器的,也就是它是指向記憶體的位址,因此使用c來編寫嵌入式軟體,或者作業系統的軟體是比較合適的選擇。下面就來看例子裡的指標語句,如下:

typedef char * va_list;

上面這句宣告了va_list為char的指標型別的別名,那麼在lcc裡又是怎麼樣處理它的呢?

先識別typedef出來,接著就調函式decl(dclglobal),然後呼叫函式specifier來處理。在函式specifier裡:

#001 //說明

#002 static type specifier(int *sclass)

#003

#032         else

#033               ty = dclr1(id, params, abstract);

#034

#035         ty = tnode(pointer, ty);

#036         break;

在第19行裡,就是處理指標的型別。

第20行獲取下乙個記號,在這句語句裡就是id(va_list)。因此在執行第33行的**,再仔細地看一下第33行**,它居然還是遞迴呼叫本函式dclr1。這就是遞迴下降的語法分析。由於指標又可以指向指標,這樣的語法一定需要遞迴地分析的。在第二執行dclr1函式裡,就執行到id的處理**:

#007  case id:               

#008         if (id)

#009        

#012         else

#013            

#016

#017         t = gettok();

#018         break;

在第10行裡就可以返回id(va_list),並返回空型別給第33行的ty。最後就是呼叫函式tnode來構造乙個指標型別,這樣就儲存va_list到符號表裡,並且宣告它是char的指標型別。

在decl函式需要把前面分析出來的基本型別放到這個指標的型別裡,它的處理**如下:

#004  type ty = dclr1(id, params, abstract);

#005

#006  for ( ; ty; ty = ty->type)

#007 

#026

#027  }

#028

#029  if (aflag >= 2 && basety->size > 32767)

#030         warning("more than 32767 bytes in `%t'/n", basety);

#031

#032  return basety;

第4行裡返回指標的型別。

在第6行裡就用for迴圈把所有型別新增到乙個鍊錶basety裡。

在第11行到第13行是呼叫ptr來新增型別到鍊錶。

在第32行就可以返回這個指標鍊錶的型別,這樣就可以給後面判斷語法和語義了。

通過上面的**就實現了指標型別的語法分析。

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...

LCC編譯器的源程式分析 37 default語句

default 語句是使用在 switch 語句的復合語句裡,它是所有其它分支不能處理時的分支處理。在 lcc裡是如下處理的 001case default 002 if swp null 003 error illegal default label n 004 else if swp defla...