2009-01-24 54 views
21

對於正則表達式,我在學習曲線上的某處,我需要使用它們來自動修改一堆C頭文件中的函數原型。有沒有人知道一個體面的正則表達式在C標頭中查找任何和所有函數原型,同時排除其他所有內容?正則表達式來提取C函數原型聲明?

編輯:起初未明確三兩件事:

  1. 關心C++中,只有直C.這意味着沒有模板等可擔心的。
  2. 該解決方案必須與typedefs和結構一起工作,不僅限於基本的C類型。
  3. 這是一種一次性的事情。它不需要很漂亮。我不在乎只要它有效就是多少,但我不想要一個複雜的,難以實施的解決方案。

回答

8

要做到這一點,你需要根據C語言語法進行解析。但是,如果這僅適用於C語言並僅適用於頭文件,那麼也許您可以採取一些快捷方式並在沒有完整的BNF的情況下獲得。

^ 
\s* 
(unsigned|signed)? 
\s+ 
(void|int|char|short|long|float|double) # return type 
\s+ 
(\w+)         # function name 
\s* 
\(
[^)]*         # args - total cop out 
\) 
\s* 
; 

這絕不是正確的,並且需要工作。但如果你願意付出一些努力並改進它,它可能代表一個起點。它可以通過跨越行,函數指針參數,MACROS和其他許多事物的函數定義來打破。

請注意,BNF 可以將轉換爲正則表達式。這將是一個大而複雜的正則表達式,但它是可行的。

+0

我懷疑經典的正則表達式不適合解析嵌套的C++模板定義。 – jfs 2009-01-24 16:21:07

+3

真的 - mercifully,他們正在處理C而不是C++。 – 2009-01-24 17:16:34

7

對於一次性練習,您可以通過簡單地開始並查看必須掃描的代碼來做到最好。選擇三個最差的標題,生成一個正則表達式或一系列正則表達式來完成這項工作。您必須決定是否以及如何處理包含函數聲明的註釋(事實上,以及包含註釋的函數聲明)。與處理:

extern void (*function(int, void (*)(int)))(int); 

(其可以是標準的C函數signal())是因爲嵌套括號在一個正則表達式強硬。如果你沒有任何這樣的函數原型,花費時間來研究如何處理它們是浪費時間。類似的評論適用於指向多維數組的指針。有可能你有文體上的約定來簡化你的生活。您不可以使用C99(C++)註釋;你不需要在他們身邊編碼。您可能不會將多個聲明放在一行中,無論是否使用通用類型 - 因此您不必處理該問題。

extern int func1(int), func2(double); double func3(int); // Nasty! 
0

比方說,你有整個c文件讀入$緩衝區。 *首先創建正則表達式,用相同數量的空格和換行符替換所有註釋,以便行和列的位置不會改變 *創建可處理括號字符串的正則表達式 *然後像這樣找到正則表達式查找函數: (static |)\ s +(\ w +)\ s * $ parenthezized_regexp + * {

此reg exp不處理函數定義使用預處理器指令的函數。

如果你去的lex/yacc的,你必須ANSI C和預處理語法結合起來,處理這些預處理指令內部函數定義

1

一個一個班輪正則表達式聽起來很辛苦。我個人使用perl腳本。這很容易。 基本問題> 1.調用你最喜歡的c預處理器來消除註釋並擴展宏。 (因此更容易) 2.計算'{''}'符號。對於純C中的函數,它們具有可預測的行爲,可以讓您檢測函數名稱。 3.將函數名稱查看原始源代碼(在進行預處理以獲取具有typedefs的簽名之前) 這是一種效率低下的方法,但對我來說效果很好。 第1步是不是真的有必要,但它會讓你的生活更輕鬆

3

假設你的代碼的格式類似

type name function_name(variables **here, variables &here) 
{ 
    code 
} 

這裏是一個班輪爲PowerShell的:

ls *.c, *.h | sls "^(\w+()?){2,}\([^[email protected]#$+%^]+?\)" 

它返回結果如:

... 
common.h:37:float max(float a, float b) 
common.h:42:float fclamp(float val, float fmin, float fmax) 
common.h:51:float lerp(float a, float b, float b_interp) 
common.h:60:float scale(float val, float valmin, float valmax, float min, 
float max) 
complex.h:3:typedef struct complex { 
complex.h:8:double complexabs(complex in) 
complex.h:13:void complexmult(complex *out, complex a, complex b) 
complex.h:20:void complexadd(complex *out, complex a, complex b) 
complex.h:27:int mandlebrot(complex c, int i) 
... 

要查看沒有文件具體的行中,添加format-table -property line(或簡稱爲ft -p line):

ls *.c, *.h | sls "^(\w+()?){2,}\([^[email protected]#$+%^]+?\)" | format-table -p line 

將返回:

Line 
---- 
void render(SDL_Surface *screen) 
void saveframe(SDL_Surface *screen) 
int handleevents(SDL_Surface *screen) 
int WinMain(/*int argc, char* args[]*/) 
void printscreen(SDL_Surface *screen, unsigned int exclude) 
void testsection(char name[]) 
void sdltests(SDL_Surface *screen, SDL_Window *window, int width, int height) 
int WinMain(/*int argc, char *argv[]*/) 
int random(int min, int max) { 
int main(int argc, char *argv[]) 

獎金:正則表達式的說明:

^(\w+(\s+)?){2,}\([^[email protected]#$+%^]+?\) 
^        Start of a line 
(  ){2,}     Create atom to appear to or more times 
           (as many as possible) 
    \w+(\s+)?      A group of word characters followed by 
           an optional space 
       \(   \) Literal parenthesis containing 
        [^[email protected]#$+%^]+? A group of 0 or more characters 
           that AREN'T in 「[email protected]#$+%^」 
1

這是一個正則表達式,它是查找C函數名稱的一個很好的起點:

^\s*(?:(?:inline|static)\s+){0,2}(?!else|typedef|return)\w+\s+\*?\s*(\w+)\s*\([^0]+\)\s*;? 

而且這些都是一些測試用例以驗證表達式:

// good cases 
static BCB_T *UsbpBufCtrlRemoveBack (BCB_Q_T *pBufCtrl); 
inline static AT91_REG *UDP_EpIER    (UDP_ENDPOINT_T *pEndpnt); 
int UsbpEnablePort (USBP_CTRL_T *pCtrl) 
bool_t IsHostConnected(void) 
inline AT91_REG *UDP_EpCSR (UDP_ENDPOINT_T *pEndpnt) 

// shouldn't match 
typedef void (*pfXferCB)(void *pEndpnt, uint16_t Status); 
    else if (bIsNulCnt && bIsBusyCnt) 
      return UsbpDump(Buffer, BufSize, Option); 

最後,這裏有一個簡單的TCL腳本通過讀取文件,並提取所有的函數原型和函數名。

set fh [open "usbp.c" r] 
set contents [read $fh] 
close $fh 
set fileLines [split $contents \n] 
set lineNum 0 
set funcCount 0 
set funcRegexp {^\s*(?:(?:inline|static)\s+){0,2}(?!else|typedef|return)\w+\s+\*?\s*(\w+)\s*\([^0]+\)\s*;?} 
foreach line $fileLines { 
    incr lineNum 
    if {[regexp $funcRegexp $line -> funcName]} { 
     puts "line:$lineNum, $funcName" 
     incr funcCount 
    }; #end if 

}; #end foreach 
puts "$funcCount functions found." 
0

隨着繼續的偉大Dean TH answer

這將找到

  • 只能使用功能,而不是返回指針

^([\w\*]+()*?){2,}\(([^[email protected]#$+%^;]+?)\)(?!\s*;)

聲明太
  • 與功能