2012-12-17 32 views
1

我在C(Linux操作系統)編程。我必須讀取一個文件,檢查該文件中的函數並打印相應的函數名稱。到目前爲止,我已經編程通過深度計算'{'來識別函數。我知道__FUNCTION__預處理器指令用於打印當前文件的函數名稱。同樣,是否有任何預處理器指令用於查找我們讀取的文件的函數名稱?我不關心任何特定的工具。我想要編程。請引導我。提前致謝。C程序找到一個c文件的函數名稱

我試圖實現此代碼。此函數採用行(它在'{')之前作爲參數。

void ffname(char line[100]) 
{ 
    int i,j,m,n,f=0; 
    char dt[10],fname[28]; 
    char s[5][10]={"int","void","struct","char","float"}; 
    dt = strtok(line," "); 
    for(i=0;i<5;i++) 
    { 
     m=strcmp(dt,s[i]); 
     if(m==0) 
     { 
      f=1; 
      n=strlen(dt); 
     } 
    } 
    if(f) 
    { 
     for(i=n+2,j=0;i<strlen(line);i++,j++) 
     { 
      if(line[i] == '*') 
       i++; 
      while(line[i] != '(') 
      { 
       fname[j]=line[i]; 
      } 
     } 
    } 
} 

我不知道這段代碼是否正確。我可以用這種方式嗎?有沒有找到函數名稱的選項?

+0

C預處理器使事情變得相當複雜。您可能需要調用預處理器,然後檢查預處理器指令被刪除後生成的文件。 – ChuckCottrill

+0

編碼標準可以使這是一個更簡單的任務。只需要使用大括號將函數左對齊,需要其他所有的縮進,並且您可以輕鬆地檢測函數 - 左對齊開括號之前的內容:-)如果您還需要空行在函數類型和簽名之前,您可以收集函數聲明和開放聲明之間的所有內容 - 也就是說,如果您可以聲明編碼標準。漂亮的打印機可以將現有的代碼轉換爲符合標準的代碼。 – ChuckCottrill

回答

2

我已經使用簡單的C代碼來查找函數的名稱。

#include <stdio.h> 
#include <string.h> 

#define SIZE 1024 
void ffname(char *line) 
{ 
    int i=1,j=0; 
    char *dt; 
    char name[SIZE]; 
    strtok(line,"("); 
    dt = strchr(line,' '); 
    if(dt[i] == '*') 
     i++; 
    while(dt[i] != '\0') 
    { 
     name[j]=dt[i]; 
     i++; 
     j++; 
    } 
    name[j] ='\0'; 
    printf("Function name is: %s\n", name); 
} 

int main(int argc, char **argv) 
{ 
    if(argc < 2) 
    { 
     printf("Give the filename \n"); 
     printf("Usage: %s filename\n", argv[0]); 
     return -1; 
    } 
    int i, lines =0, funlines =0,count =0, fn =0, flag =0; 
    char c[SIZE],b[SIZE]; 
    FILE *fd; 
    fd = fopen(argv[1],"r"); 
    while(fgets(c,SIZE,fd)) 
    { 
     lines++; 
     i=0; 
     for(i=0;i<strlen(c);i++) 
     { 
      while(c[i] =='\t' || c[i] == ' ') 
      { 
       i++; 
      } 
      if(c[i] == '{') 
      { 
       count++; 
       if(flag) 
       { 
        funlines++; 
       } 
       if(count == 1) 
       { 
        fn++; 
        printf("Function %d is Started..............\n", fn); 
        flag = 1; 
        ffname(b); 
       } 
       break; 
      } 
      else if(c[i] == '}') 
      { 
       count--; 
       if(!count) 
       { 
        flag = 0; 
        printf("No of lines in the function %d is: %d\n", fn, funlines); 
        printf("Function %d is finished..........\n", fn); 
        funlines = 0; 
       } 
       else 
       { 
        funlines++; 
       } 
       break; 
      } 
      else if(flag) 
      { 
       funlines++; 
       break; 
      } 
     } 
     strcpy(b,c); 
    } 
    printf("Total no of function%d\n",fn); 
    printf("Total no of lines%d\n",lines); 
    return 0; 
} 
-1

我想你可以嘗試 正則表達式發現如果目標函數名存在。

你可以在這篇文章中找到關於正則表達式的更多信息。 Regular expressions in C: examples?

+1

不,您不能使用正則表達式在任意c文件中查找函數。正則表達式不擅長尋找匹配的開放/關閉信號。你需要某種語法......就像一個C編譯器。 – xaxxon

+0

專門打開/關閉任意深度的標識符。 – xaxxon

0

你讀什麼樣的文件?它是一些任意C源文件?如果是,它可以用許多不同的方式定義功能,例如,通過預處理器宏。例如用

#define DF(Nam) void Nam##print(void) {puts(#Nam);} 

C文件可以具有DF(foo)和已定義的函數fooprint(沒有在源代碼中的任何fooprint發生)。

如果您想處理編譯器看到的一組函數名稱,最好開發一個編譯器擴展或插件。使用GCC,您可以使用MELT(特定領域的語言來擴展GCC)。

如果您想查找由某個目標文件*.o定義的[global]功能,可以在Linux上使用nm命令。也許還應考慮dlopen(3)-共享目標文件*.so

當然,所有這些都可能是編譯器和系統特定的。

+0

在我的情況下,我將讀取任何類型的C文件,這些文件可能或可能不會被定義爲預處理器宏。有沒有用於查找函數名稱的僞代碼? – Dhasneem

+0

不......因爲預處理器的技巧可以做奇怪的事情,正如我所展示的。如果你想讀取任何C文件,你最好擴展編譯器來處理它。 –

1

這很難做到正確。基本上,你需要實現一個C編譯器才能正確執行此操作。這正是c編譯器所做的,並且需要一個合適的語法定義和預處理器來執行此操作。

3

我假設你正在閱讀的文件是一個C源文件。

這不是一項簡單的任務,如果你想正確地做到這一點(意思是說,如果你想可靠地識別所有功能)。有關其他信息,請參見Listing C/C++ functions (Code analysis in Unix)

我不關心任何特定的工具。我想要編程。

這當然是可能的,但你將基本結束了一個掃描儀/分析器前端爲C,類似於已經在工具,如DoxygenSynopsis實現。您可以稍微簡化一下並使用一些啓發式方法,例如,您不需要解析完整的代碼(例如,您可以跳過{}之間的任何內容)。

如果你仍然想實現自己的方式,我會請按照下列步驟操作:

  • 在任何情況下,你應該運行通過C預處理器的C文件首先要解決任何宏,並有原始C代碼可用。
  • 然後熟悉基本的Compiler Construction技術,特別是掃描和Parsing你的源文件和C語法。請注意,有不同的語法,具體取決於您使用的C版本。例如,ISO/IEC 9899:TC2, Annex A1包含C99的語法。查看上述工具的源代碼也應該有所幫助。
  • 實現一個掃描器來標記輸入,並實現一個識別函數名稱的解析器。從我之前提到的語法中,(6.9.1) function-definition是您應該從頭開始的生產術語。
1

因爲C支持這麼多的語法,所以編寫C的解析器很困難(不是不可能,很難)。

您可以定義使用功能

  1. 標準C的風格,擁有標準的返回類型
  2. 標準C的風格,用typedef /枚舉等返回類型(無法簡單用簡單的語法分析器可以識別。你會需要建立用戶定義的數據類型的數據庫文件)
  3. C代碼宏(參見巴西萊的answer例如)
  4. 大會(解析一個非常簡單的通過test.c以向gcc -S知道語法)我已經使用這個方法創建一些佔位符函數。

因此,不是解析C文件,而是更容易解析程序集文件。

E.g. gcc -S翻譯如下C函數的定義:

.globl someFnName 
    .type someFnName, @function 
someFnName: 
    ...function-body related code... 

如果你只想要的功能名稱列表(即不需要參數/返回值等),你可以很容易地分析上面的3行代碼彙編,與C文件相比。
如果您還將-g開關與-s一起添加,您還可以獲得一些行號信息。

優點:

  1. 更容易比C文件
  2. 需要照顧的大部分(如果不是全部)的方法來定義一個函數來解析。
  3. 根據「.globl someFnName」行的存在與否,可以分離靜態函數。

缺點:

  1. 需要外部解析器 - 海灣合作委員會或其他一些
  2. 編譯器需要
  3. 可給予一定的誤報
1

我覺得flex(GCC)依賴二級解析器和bison將幫助你解決你的問題,這裏有一些鏈接:c grammar(lex)c grammar(bison)

+0

構建一個詞法分析器和解析器是最好的方法,但需要一定的知識。這裏插入更多細節來解釋如何 - 特別是發佈函數名稱,返回類型和簽名的語法註釋將很有用。 – ChuckCottrill

0

如果你可以使用GCC的:

gcc -nostdinc -aux-info output demo.c 

僅輸出文件的功能(不包括標準庫)

注:-nostdinc原因編譯錯誤

你能避免編譯錯誤使用sed

gcc -aux-info output demo.c 
sed '/include/d' output 
1

簡單的方法,如果你是願意做一些假設,在源代碼中讀取,那麼:

  • 刪除任何preprosessor指令(假設你不想從包含文件的功能,並且不想處理任何靠不住#define宏可能與功能,請注意多行#define(續行\))。

  • 刪除任何評論(小心嵌套/*評論)。

  • 將任意字符串轉換爲""(注意轉義的\"和多行字符串)。

  • 轉換任何字符到' '或東西(擺脫'{'等,要小心躲過\'以及其它逃逸)。

  • 將所有(嵌套,多行)代碼塊轉換爲「頂級」{}對。

  • 格式化爲線突破後,才;},除了加入一行上一行孤獨;文本,在情況下,它實際上是的};哪些不是函數定義的一部分。

  • 刪除其中到底有何線;

除非我錯過了一些東西,現在你應該會留下所有的函數定義,每行一個,使用函數體{}取代。

+0

謝謝。你的算法真的很有用。 – Dhasneem

+0

@ Dhasneem謝謝。編輯了一下,最重要的是第二個子彈。 – hyde

+0

謝謝你的信息。我沒有注意到這一點。 – Dhasneem