跳轉到內容

GNU C 編譯器內部/建立編譯器擴充套件 3 4

來自華夏公益教科書

在本節中,我們將逐步描述如何建立一個新的編譯器擴充套件。首先,需要下載 GCC 並用 GEM 補丁修補它。之後,可以開始編寫編譯器擴充套件。當擴充套件準備就緒後,就可以使用修補後的 GCC 版本和新的編譯器擴充套件來編譯其他程式。

這裡 下載 GEM 框架。解壓縮它並輸入 make all。這將下載 GCC 的副本,用 GCC 補丁修補它,編譯和安裝 GCC,並構建示例。

C 函式過載示例允許使用者像在 C++ 中一樣在 C 中過載函式。

  /* one function */
  void test(int a, int b) {
    printf("%d %d\n", a, b);
  }
  /* overloaded function */
  void test(char *a, int b) {
    printf("%s %d\n", a, b);
  }
  void main() {
    test(1,2);
    test("abc", 1);
  }

讓我們更詳細地考慮 CFO 示例。

C 函式過載

[編輯 | 編輯原始碼]

擴充套件的原始碼位於 ./examples/cfo/cfo.c 檔案中。以下掛鉤已實現

 gem_start_decl()
 gem_start_function()
 gem_build_function_call()

實現的思路是修改每個多次宣告的函式的名稱。這些函式的名稱被修改為包含引數的型別資訊。例如,函式 test(int, int) 被重新命名為 test_i_i(int, int)。重新命名發生在函式 cfo_alias_decl() 中。

函式 cfo_start_decl() 和 gem_start_function() 呼叫此函式。它查詢正在宣告的函式的名稱,如果未找到,則立即返回。

 cfo_find_symtab(&t_func, func_name);
 if (t_func==NULL_TREE || DECL_BUILT_IN(t_func)) {
   return;
 }

因此,非過載函式的名稱不會改變。這保持了與未修改編譯器的相容性。

如果以前聲明瞭具有此名稱的函式,則擴充套件會檢查是否建立了包含引數型別資訊的別名。

 strcpy(new_name, func_name);
 strcat(new_name, cfo_build_name(TREE_PURPOSE(T_O(declarator, 1))));
 cfo_find_symtab(&t_func_alias, name);

函式 cfo_build_name() 構建函式引數的名稱。如果以前沒有建立別名,則建立別名。

   t_alias_attr=tree_cons(get_identifier("alias"),
                          tree_cons(NULL_TREE, get_identifier(name), NULL_TREE), NULL_TREE);
   TYPE_ATTRIBUTES(T_T(t_func)) = t_alias_attr;
   DECL_ATTRIBUTES(t_func)=t_alias_attr;

最後,新的宣告被重新命名,以便包含引數的型別資訊。

   T_O(declarator,0) = get_identifier(new_name);

函式 cfo_build_function_call() 構建包含引數型別資訊的函式名稱,並在符號表中查詢它。如果找到名稱,則在函式呼叫中替換函式名稱。如果未找到名稱,則函式未過載,並且正在呼叫的函式的名稱不會改變。構建新名稱

 name = cfo_build_decl_name(t_func, t_parm);

檢查此識別符號是否以前被解析過

 t_new_func = get_identifier(name);

如果是,則獲取宣告

 if (t_new_func) {
   t_new_func = lookup_name(t_new_func);
 }

如果找到宣告,則替換函式

 *func = t_new_func;
上一個: GEM 框架 C 中的函式過載 下一個: GCC 駭客
華夏公益教科書