1. 程式人生 > >gcc 原始碼分析-前端篇2

gcc 原始碼分析-前端篇2

2. 對ID及保留字的處理
   在c語言中,系統預留了很多關鍵字,也被稱為保留字,比如表示資料型別的int,short,char,控制分支執行的if,then等。
   任何關鍵字,本質上也是一個ID,比如它也有長度,對int就是3,對short就是5,也有內容,比如int,short。但比起一般id,
   它還有其他一些屬性,比如表示資料型別的int,它有一個數值範圍,它的值範圍是-xxx到xxx之間。
   由於這樣的關係,gcc把ID和關鍵字都儲存在一張表中,這張表定義如下:
                                         #define MAX_HASH_TABLE 1009
                                          tree hash_table[MAX_HASH_TABLE];    /* id hash buckets */
   同時定義了一個函式get_identifier (text) 來操縱這一張表:
       
       函式具體實現就是通過傳入的字串查詢該id,如果沒有則建立這個ID,這裡new了一個tree_identifier, 同時把它儲存在hash_table表中,為了加快查詢,這裡用到了hash演算法。在這裡我們見到了struct tree_common結構體chain成員的用法,對於hash演算法來說,很難避免衝突,對於傳入的不同字串,有可能它算出的hash值是一樣的,這時候,我們就把相沖突的ID放在chain成員變數中;
      函式的最後給tree_identifier的成員length,pointer附值。

   gcc 在執行之初,便開始建立這些表示資料型別的關鍵字,比如int,short,char,void,這個在函式init_lex依次建立,並把建立的相對應的
   tree 結點附給:
        ridpointers[(int) RID_INT]
        ridpointers[(int) RID_CHAR]
        ridpointers[(int) RID_VOID]
        ridpointers[(int) RID_SHORT]

   關鍵字的ID生成了,還有附一些其他引數,這個過程是在init_decl_processing完成;在GCC中要表示一個數據型別,要用到下面的結構:

struct tree_type
{
  char common[sizeof (struct tree_common)];
  union tree_node *values;
  union tree_node *sep;
  union tree_node *size;

  enum machine_mode mode : 8;
  unsigned char size_unit;
  unsigned char align;
  unsigned char sep_unit;

  union tree_node *pointer_to;
  union tree_node *reference_to;
  int parse_info;
  int symtab_address;
  union tree_node *name;
  union tree_node *max;
  union tree_node *next_variant;
  union tree_node *main_variant;
  union tree_node *basetypes;
  union tree_node *noncopied_parts;
  /* Points to a structure whose details depend on the language in use.  */
  struct lang_type *lang_specific;
};
   在表示int型的資料型別中,它的兩個成員變數sep,max比較重要; sep表示它的最小值,而max表示它的最大值;

   在函式make_signed_type中建立了一個 INTEGER_TYPE 型別的tree 節點;它實際上是一個 struct tree_type 型別的節點,
   在該函式中,建立的節點的sep,max成員被賦予INTEGER_CST 節點,它實際上是一個struct tree_int_cst型別節點:
struct tree_int_cst
{
  char common[sizeof (struct tree_common)];
  long int_cst_low;
  long int_cst_high;
};

  可以看出,它有兩個成員特殊成員:int_cst_low,int_cst_high
  對於最小值,它給出的值是: int_cst_low=0x80000000,int_cst_high=0xffffffff
  對於最大值,它給出的值是:int_cst_low=0x7fffffff,int_cst_high=0x0

  它們均是在build_int_2 函式中建立;
  在函式make_signed_type的最後layout_type中,設定int 型資料節點的size成員,它也是一個struct tree_int_cst型別節點,只是它的
   int_cst_low值是4,而int_cst_high為0;

   這樣int型節點生成了,這個節點資料和它的ID,最後被封裝成一個宣告型別節點,它用struct tree_decl結構體表示:
struct tree_decl
{
  char common[sizeof (struct tree_common)];
  char *filename;
  int linenum;
  union tree_node *size;
  enum machine_mode mode : 8;
  unsigned char size_unit;
  unsigned char align;
  unsigned char voffset_unit;
  union tree_node *name;
  union tree_node *context;
  int offset;
  union tree_node *voffset;
  union tree_node *arguments;
  union tree_node *result;
  union tree_node *initial;
  char *print_name;
  char *assembler_name;
  struct rtx_def *rtl;    /* acts as link to register transfer language
                   (rtl) info */
  int frame_size;        /* For FUNCTION_DECLs: size of stack frame */
  struct rtx_def *saved_insns;    /* For FUNCTION_DECLs: points to insn that
                   constitutes its definition on the
                   permanent obstack.  */
  int block_symtab_address;
  /* Points to a structure whose details depend on the language in use.  */
  struct lang_decl *lang_specific;
};


  可以看出,這是一個巨複雜的結構,int 型別節點轉變成一個int 宣告節點過程中,它將生成一個struct tree_decl節點,它的
  成員變數name將是int 的ID節點值,它的type 就是剛剛生成的int 節點,這個int 宣告節點最後會被放入到記錄全域性節點的
  global_binding_level中,
  global_binding_level->name 指向剛剛建立的int 宣告節點;

  在init_decl_processing函式接下來將建立char 型別節點,unsigned int 型別,short 型別,這些值都回放入global_binding_level->name
  然後通過chain連線起來;   

  總結一下,gcc 用hash表來儲存所有的ID,包括保留字;gcc 對於內建的資料型別(int,short,char)在初始化時會生成tree_decl 結構的結點,
  並把它記錄在global_binding_level的name變數中,這個name始終指向最後一個宣告的結點,並通過節點的chain串接起來。