当谈到正则表达式时,我在学习曲线上的某个地方,我需要使用它们来自动修改一堆C头中的函数原型.有没有人知道一个不错的正则表达式来查找C头中的任何和所有函数原型,同时排除其他所有内容?
编辑:最初不清楚的三件事:
Qua*_*noi 17
您可以使用ANSI C yacc/lex语法实现解析器.
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 可以转换为正则表达式.它将是一个庞大而复杂的正则表达式,但它是可行的.
对于一次性练习,您可能最好从简单开始并查看您必须扫描的代码.选择三个最差的标题,生成一个正则表达式或一系列正则表达式来完成这项工作.您必须决定是否以及如何处理包含函数声明的注释(实际上,包含注释的函数声明).处理:
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)
假设您的代码格式化为
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)