通过词法分析实现的指出C程序中包含的头文件
在阅读有些程序的源码时,很希望能够马上弄清楚源码中到底包含了哪些头文件,以确定是否需要为了特殊的函数而手动加入#include。借助flex的词法分析实现了这一功能,本质上就是对正则表达式的匹配。注意这个程序不能够处理包含嵌套的情形(也就是说不能指出包含文件包含了哪些文件),感兴趣的可以通过栈来实现。源码如下:
1 /*源代码:ic.l*/ 2 3 /*定义文件预处理指令文件名起始状态*/ 4 %x IFILE 5 6 %% 7 ^"#"[ \t]*include[ \t]*[\"<] {BEGIN IFILE;} /*#include的多种表达方式的正则表达式*/ 8 <IFILE>[^\t\n\">]+ {/*进入文件名状态*/ 9 printf("%d:%s\n",yylineno++,yytext);/*输出行号和文件名,yylineno是flex定义的全局变量,yytext是当前 10 输入流*/ 11 { 12 char c; 13 /*去处行尾可能的换行符*/ 14 while((c=input()) && c!='\n'); 15 } 16 /*回复至初始状态*/ 17 BEGIN INITIAL; 18 }/*下面的RE用于处理行首换行(空行)和换行的情况,增加yylineno的值*/ 19 ^\n {++yylineno;} 20 \n {++yylineno;} 21 . {/*直接忽略*/} 22 %% 23 24 int main(int argc,char *argv[]) 25 { 26 /*命令行读取文件名参数*/ 27 if (argc<2) 28 { 29 fprintf(stderr,"Usage:%s filename\n",argv[0]); 30 } 31 FILE *f; 32 int i; 33 /*循环打开文件*/ 34 for (i=1;i<argc;++i) 35 { 36 f=fopen(argv[i],"r"); 37 if (!f) 38 { 39 perror(argv[i]); 40 exit(EXIT_FAILURE); 41 } 42 /*重新开始输入*/ 43 yyrestart(f); 44 yylineno=1; 45 /*开始新的文件,函数初始化为1*/ 46 printf("\t%s:\n",argv[i]); 47 yylex();/*开始词法分析*/ 48 printf("\n"); 49 fclose(f); 50 } 51 return 0; 52 }
编译指令:
1 $flex -o ic.lex.c ic.l 2 $gcc -o ic ic.lex.c -lfl
示范运行结果:
1 $ ./ic test_inc.c inc_count.lex.c 2 test_inc.c: 3 1:stdio.h 4 5 inc_count.lex.c: 6 20:stdio.h 7 21:string.h 8 22:errno.h 9 23:stdlib.h 10 43:inttypes.h 11 487:unistd.h
可见已经达到了目的。
不要想你能为世界做什么,想想你该为世界做什么!