正则表达式拉出C函数原型声明?

当谈到正则表达式时,我在学习曲线上的某个地方,我需要使用它们来自动修改一堆C头中的函数原型。 有没有人知道一个不错的正则表达式来查找C头中的任何和所有函数原型,同时排除其他所有内容?

编辑:最初不清楚的三件事:

  1. 关心C ++,只关心C.这意味着没有模板等担心。
  2. 该解决方案必须与typedef和structs一起使用,不仅限于基本的C类型。
  3. 这是一种一次性的事情。 它不需要漂亮。 只要它有效,我不在乎它有多大,但我不想要一个复杂的,难以实施的解决方案。

您可以使用ANSI C yacc / lex语法实现解析器。

要正确执行此操作,您需要根据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 可以转换为正则表达式。 它将是一个庞大而复杂的正则表达式,但它是可行的。

对于一次性练习,您可能最好从简单开始并查看您必须扫描的代码。 选择三个最差的标题,生成一个正则表达式或一系列正则表达式来完成这项工作。 您必须决定是否以及如何处理包含函数声明的注释(实际上,包含注释的函数声明)。 处理:

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

(由于嵌套的括号,它可能是标准C函数signal() )在正则表达式中很难。 如果你没有任何这样的函数原型,那么花时间研究如何处理它们就浪费了时间。 类似的注释适用于指向多维数组的指针。 您可能会有风格惯例来简化您的生活。 您不能使用C99(C ++)注释; 你不需要围绕它们编码。 您可能不会在一行中放置多个声明,无论是否有共同类型 – 因此您不必处理它。

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

假设你的代码格式是这样的

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

这是Powershell的单线程:

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

返回结果如下:

 ... 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,}\([^!@#$+%^]+?\)" | 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,}\([^!@#$+%^]+?\) ^ 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 [^!@#$+%^]+? A group of 0 or more characters that AREN'T in “!@#$+%^” 

单线版正则表达式听起来很难。 我个人使用perl脚本。 这很容易。 基本方法是> 1.调用您最喜欢的c预处理器以消除注释并扩展宏。 (所以它更容易)2。计算'{”}’符号。 对于普通C中的函数,它们具有可预测的行为,允许您检测函数名称。 3.将函数名称查找到原始源代码(在预处理之前获取具有typedef的签名)这是一种效率低下的方法,但它对我来说非常有效。 第一步不是必要的,但它会让你的生活更轻松

这是一个正则表达式,是查找C函数名称的良好起点:

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

这些是validation表达式的一些测试用例:

 // 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." 

假设您将整个c文件读入$ buffer。 *首先创建regexp,用相同数量的空格和换行符替换所有注释,这样行和col位置不会改变* create regexp可以处理带括号的字符串*然后像这样的regexp找到函数:(static |)\ s +(\ w + )\ S * $ parenthezized_regexp + * {

这个reg exp不处理函数定义使用预处理器指令的函数。

如果你选择lex / yacc,你必须结合ansi c和预处理器语法来处理函数定义中的那些预处理器指令

继续伟大的Dean TH回答

这会找到

  • 只有function而不是声明
  • 和返回指针的函数

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