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

dsi*_*cha 24 c regex function

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

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

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

Qua*_*noi 17

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

  • 我不能重复它.正则表达式不能替代解析器.+1. (5认同)
  • 乍一看答案似乎不错,但尝试遵循它就会发现,简单的语法解析器是一个糟糕的选择。显然,它需要在将代码传递给解析器之前进行预处理,这本身就需要付出巨大的努力。但即便如此,解析器也会因 typedef 指定的自定义类型而卡住。正如[此常见问题解答](http://www.quut.com/c/ANSI-C-grammar-FAQ.html)中所述,需要创建语义分析器,这是一项艰巨的任务。可悲的是,解析器对于教育来说很有用,但在实际解决手头的任务时效率非常低,这确实可以使用正则表达式来完成,而不那么痛苦。 (2认同)

Pau*_*ham 10

要正确执行此操作,您需要根据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*
;
Run Code Online (Sandbox Code Playgroud)

这绝不是正确的,需要工作.但如果你愿意付出一些努力并改进它,它可能代表一个起点.它可以被跨越行,函数指针参数,MACROS和许多其他东西的函数定义所打破.

请注意,BNF 可以转换为正则表达式.它将是一个庞大而复杂的正则表达式,但它是可行的.

  • 真实 - 仁慈地说,他们处理C而不是C++. (3认同)

Jon*_*ler 7

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

extern void (*function(int, void (*)(int)))(int);
Run Code Online (Sandbox Code Playgroud)

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

extern int func1(int), func2(double); double func3(int);  // Nasty!
Run Code Online (Sandbox Code Playgroud)


999*_*ars 5

假设您的代码格式化为

type name function_name(variables **here, variables &here)
{
    code
}
Run Code Online (Sandbox Code Playgroud)

这是Powershell的单线程:

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

返回结果如下:

...
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)
...
Run Code Online (Sandbox Code Playgroud)

要了解刚才没有文件具体的行中,添加format-table -property line(或简称ft -p line):

ls *.c, *.h | sls "^(\w+( )?){2,}\([^!@#$+%^]+?\)" | format-table -p line
Run Code Online (Sandbox Code Playgroud)

哪个回报:

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[])
Run Code Online (Sandbox Code Playgroud)

奖励:正则表达式的解释:

^(\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 “!@#$+%^”
Run Code Online (Sandbox Code Playgroud)


小智 5

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

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

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

// 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);
Run Code Online (Sandbox Code Playgroud)

最后,这是一个简单的 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."
Run Code Online (Sandbox Code Playgroud)