對於正則表達式,我在學習曲線上的某處,我需要使用它們來自動修改一堆C頭文件中的函數原型。有沒有人知道一個體面的正則表達式在C標頭中查找任何和所有函數原型,同時排除其他所有內容?正則表達式來提取C函數原型聲明?
編輯:起初未明確三兩件事:
- 我不關心C++中,只有直C.這意味着沒有模板等可擔心的。
- 該解決方案必須與typedefs和結構一起工作,不僅限於基本的C類型。
- 這是一種一次性的事情。它不需要很漂亮。我不在乎只要它有效就是多少,但我不想要一個複雜的,難以實施的解決方案。
對於正則表達式,我在學習曲線上的某處,我需要使用它們來自動修改一堆C頭文件中的函數原型。有沒有人知道一個體面的正則表達式在C標頭中查找任何和所有函數原型,同時排除其他所有內容?正則表達式來提取C函數原型聲明?
編輯:起初未明確三兩件事:
您可以使用ANSI C yacc/lex grammar來實現解析器。
要做到這一點,你需要根據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 可以將轉換爲正則表達式。這將是一個大而複雜的正則表達式,但它是可行的。
我懷疑經典的正則表達式不適合解析嵌套的C++模板定義。 – jfs 2009-01-24 16:21:07
真的 - mercifully,他們正在處理C而不是C++。 – 2009-01-24 17:16:34
對於一次性練習,您可以通過簡單地開始並查看必須掃描的代碼來做到最好。選擇三個最差的標題,生成一個正則表達式或一系列正則表達式來完成這項工作。您必須決定是否以及如何處理包含函數聲明的註釋(事實上,以及包含註釋的函數聲明)。與處理:
extern void (*function(int, void (*)(int)))(int);
(其可以是標準的C函數signal()
)是因爲嵌套括號在一個正則表達式強硬。如果你沒有任何這樣的函數原型,花費時間來研究如何處理它們是浪費時間。類似的評論適用於指向多維數組的指針。有可能你有文體上的約定來簡化你的生活。您不可以使用C99(C++)註釋;你不需要在他們身邊編碼。您可能不會將多個聲明放在一行中,無論是否使用通用類型 - 因此您不必處理該問題。
extern int func1(int), func2(double); double func3(int); // Nasty!
比方說,你有整個c文件讀入$緩衝區。 *首先創建正則表達式,用相同數量的空格和換行符替換所有註釋,以便行和列的位置不會改變 *創建可處理括號字符串的正則表達式 *然後像這樣找到正則表達式查找函數: (static |)\ s +(\ w +)\ s * $ parenthezized_regexp + * {
此reg exp不處理函數定義使用預處理器指令的函數。
如果你去的lex/yacc的,你必須ANSI C和預處理語法結合起來,處理這些預處理指令內部函數定義
一個一個班輪正則表達式聽起來很辛苦。我個人使用perl腳本。這很容易。 基本問題> 1.調用你最喜歡的c預處理器來消除註釋並擴展宏。 (因此更容易) 2.計算'{''}'符號。對於純C中的函數,它們具有可預測的行爲,可以讓您檢測函數名稱。 3.將函數名稱查看原始源代碼(在進行預處理以獲取具有typedefs的簽名之前) 這是一種效率低下的方法,但對我來說效果很好。 第1步是不是真的有必要,但它會讓你的生活更輕鬆
假設你的代碼的格式類似
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]#$+%^」
這是一個正則表達式,它是查找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."
隨着繼續的偉大Dean TH answer
這將找到
^([\w\*]+()*?){2,}\(([^[email protected]#$+%^;]+?)\)(?!\s*;)
我無法重複。正則表達式不能代替解析器。 +1。 – dmckee 2009-01-25 01:16:04