C語言列舉型別的語法分析和型別系統實現

2021-07-23 23:40:57 字數 4109 閱讀 6294

本節,我們看看對於列舉型別,c語言編譯器是如何解析的。我們使用下面的例項去實現語法解析和型別系統的建立:

enum

tag x;

上面的列舉定義會被c編譯器轉義成下面的形式:

enum tag;

int x;

int a = 0;

int b = 1;

int c = 5;

int d = 6

上面的**中,enum被當做一種資料型別, x 被當做整形對待,tag和x沒什麼用,會在最終生成**中給拋棄掉。

我們先看看列舉型別的解析語法:

type_specifier -> enum_specifier

enum_specifier -> enum_nt name_nt opt_enum_list

enum_nt -> enum

enumerator_list -> enumerator

emerator_list -> enumerator_list comma enumerator

enumerator -> name_nt

name_nt -> name

enumerator -> name_nt equal const_expr

const_expr -> number

opt_enum_list -> lc enumerator_list rc

從上面語法中,我們可以看到enum其實是關鍵字enum的標籤,enumrator對應列舉型別中的變數定義,例如 a, b就對應於非終結符enumrator, 列舉型別中的變數賦值,例如 int c = 5, 對應非表示式:enumerator -> name_nt equal const_expr。

我們看看解析器對列舉型別的解析流程:

1: 讀取關鍵字enum, 並返回標籤enum.

2: 通過表示式enum_nt -> enum 進行reduce, 此時設定乙個全域性變數enumval為0,這個全域性變數的值將會在後面賦值給各個列舉變數。

3:讀入變數名tag, 通過name_nt -> name 進行reduce, 此時為tag建立乙個symbol物件,於是屬性堆疊便有了乙個物件:

4: 讀入左括號,返回標籤lc, 讀入變數a, 返回標籤name,通過name_nt -> name做reduce, 同時為變數a構建乙個symbol 物件,於是屬性堆疊如下:

5: 根據enumerator -> .name_nt 做reduce,此時生成乙個specifier物件,specifier 的型別設定為constant, 並將全域性變數enumval的值0,同時增加enumval的值,讓enumval從0變為1。設定到specifier物件裡,同時將該物件加入變數a 對應symbol的型別列表:

6: 根據表示式enumerator_list -> .enumerator做reduce, 同時把堆疊頂部的symbol物件出棧,由於該symbol物件已經加入符號表,因此出棧不影響後面生成**。

7:讀入逗號,返回標籤comma, 讀入變數名b,返回標籤name, 通過name_nt -> .name進行reduce的同時,為b生成乙個symbol物件。

8: 根據表示式enumerator -> .name_nt構造specifier物件,將物件的constantvalue域設定成enumval, 此時enumval的值是1:

9: 此時解析堆疊頂部的非終結符滿足表示式:enumerator_list -> .enumerator_list comma enumerator ,於是進行reduce,同時將當前頂部的symbol出棧,並將左邊的非終結符:enumerator_list壓入解析堆疊

10:讀入逗號,讀入變數c, 根據表示式name_nt -> .name進行reduce, 同時生成乙個symbol物件。

11: 讀入等號,返回標籤equal, 讀入等號後面的數字,返回標籤number,通過表示式const_expr -> number 進行reduce, 同時將數字壓入到屬性堆疊。

12: 根據表示式enumerator -> .name_nt equal const_expr 進行reduce, 為前面生成的symbol構造乙個specifier物件,同時把上一步壓入屬性堆疊的數值取出,賦值給全域性表裡enumval, 並將變數的值設定到specifier物件中,然後enumval的值加1,使得它的值為6:

13: 再次根據表示式enumerator_list -> .enumerator_list comma enumerator 進行reduce, 將屬性堆疊頂部的symbol物件出棧。並將enumerator_list壓入解析堆疊。

14: 讀入逗號,讀入變數d,返回標籤name, 根據表示式name_nt -> .name進行reduce,同時生成乙個symbol物件。

15: 根據表示式enumerator -> .name_nt, reduce時,生成乙個specifier物件,將它的constantvalue的值設定成enumval, 也就是6,同時讓enumval加1變成7:

16: 再次根據表示式enumerator_list -> .enumerator_list comma enumerator 進行reduce, 將屬性堆疊頂部的symbol出棧,同時在解析堆疊壓入非終結符enumerator_list 。

17:讀入右括號}, 跟著使用表示式:opt_enum_list -> .lc enumerator_list rc 進行reduce, 然後再根據表示式:enum_specifier -> .enum_nt name_nt opt_enum_list 做reduce.

18: 根據表示式type_specifier -> .enum_specifier做reduce,此時生成乙個specifier物件,它的型別是int:

接著再根據表示式:type_or_class -> .type_specifier, specifiers -> .type_or_class, opt_specifiers -> .specifiers 連續進行reduce, 將非終結符opt_specifiers壓入解析堆疊。

19: 將右括號後面的x讀入,返回標籤name, 根據表示式 new_name -> .name 進行reduce, 同時為變數x生成乙個symbol物件:

接著再根據表示式:var_decl -> .new_name,ext_decl -> .var_decl,ext_decl_list -> .ext_decl 進行reduce, 把非終結符ext_decl_list壓入解析堆疊。

20: 讀入最後的分號,得到標籤semi, 根據表示式ext_def -> .opt_specifiers ext_decl_list semi 進行reduce, 同時把specifier物件新增到x變數對應的symbol物件的型別列表中:

21: 根據表示式:ext_def_list -> .ext_def_list ext_def進行reduce,同時將堆疊上的symbol物件出棧。然後全域性非終結符被壓入堆疊,此時解析流程結束,進入接收狀態。

C 語言的布林型別和列舉型別

布林型別物件可以被賦予文字值true或者false,所對應的關係就是真於假的概念!我們通常使用的方法是利用他來判斷條件的真於假,例如如下的 c 如果乙個變數你需要幾種可能存在的值,那麼就可以被定義成為列舉型別。之所以叫列舉就是說將變數或者叫物件可能存在的情況也可以說是可能的值一一例舉出來。舉個例子來...

C語言列舉型別

在實際問題中,有些變數的取值被限定在乙個有限的範圍內。例如,乙個星期內只有七天,一年只有十二個月,乙個班每週有六門課程等等。如果把這些量說明為整型,字元型或其它型別顯然是不妥當的。為此,語言提供了一種稱為 列舉 的型別。在 列舉 型別的定義中列舉出所有可能的取值,被說明為該 列舉 型別的變數取值不能...

C語言列舉型別

實際問題中,有些變數的取值被限制在一定範圍內。例如,乙個星期內只有七天,一年只有十二個月,乙個班每週有六門課程等。c語言提供了一種 列舉 enum 型別,可以列出所有可能的取值。定義形式為 enum 變數名 這些值也稱為 列舉元素 注意最後的分號 不能少。例如,列出乙個星期有幾天 enum week...