用flex写的一个简单代码统计工具
学习编译原理,看完词法分析,对它有了一个大致的了解,便写了下面的例子。这个例子统计C或C++代码中有多少行注释,多少行代码。实现简单,但功能还不错。
这里用到了正则表达式,flex的用法,windows批处理的编程知识。
stat.c文件:实现对一个文件进行统计。
这里用到了正则表达式,flex的用法,windows批处理的编程知识。
stat.c文件:实现对一个文件进行统计。
/*
stat.c
*/
% option noyywrap
%{
#include < stdio.h >
/* 一行内既有代码又有注释, 则codeno,commentno都加一 */
int lineno = 0 ; /* 总行数 */
int emptylineno = 0 ; /* 空行数 */
int codeno = 0 ; /* 代码行数 */
int commentno = 0 ; /* 注释行数 */
int is_comment = 0 ; /* 该行是否为注释 */
int in_comment = 0 ; /* 是否在注释内,主要考虑跨行的注释代码 */
int is_code = 0 ; /* 该行是否为代码 */
%}
%%
\/\/ { is_comment = 1 ; } /* 匹配以 // 开始的注释 */
\/\* { in_comment = 1 ; is_comment = 1 ; } /* 匹配另一种注释 */
\*\/ { in_comment = 0 ; is_comment = 1 ; }
[ ^ \ t \ n] { if (in_comment) is_comment = 1 ; else is_code = 1 ; } /* 非空格字符 */
\ n { /* 一行结束了,分析这行的属性 */
lineno ++ ;
if (!is_comment && !is_code)
emptylineno ++ ;
else
{
if (is_comment)
commentno ++ ;
if (is_code)
codeno ++ ;
}
is_comment = 0 ;
is_code = 0 ;
}
. { ; } /* 匹配漏掉的字符,使它不输出 */
%%
int main()
{
yylex();
/* 匹配最后一行 */
if (is_comment)
{
lineno ++ ;
commentno ++ ;
}
else if (is_code)
{
lineno ++ ;
codeno ++ ;
}
printf( " %d\t%d\t%d\t%d\n " , lineno, emptylineno, commentno, codeno);
return 0 ;
}
% option noyywrap
%{
#include < stdio.h >
/* 一行内既有代码又有注释, 则codeno,commentno都加一 */
int lineno = 0 ; /* 总行数 */
int emptylineno = 0 ; /* 空行数 */
int codeno = 0 ; /* 代码行数 */
int commentno = 0 ; /* 注释行数 */
int is_comment = 0 ; /* 该行是否为注释 */
int in_comment = 0 ; /* 是否在注释内,主要考虑跨行的注释代码 */
int is_code = 0 ; /* 该行是否为代码 */
%}
%%
\/\/ { is_comment = 1 ; } /* 匹配以 // 开始的注释 */
\/\* { in_comment = 1 ; is_comment = 1 ; } /* 匹配另一种注释 */
\*\/ { in_comment = 0 ; is_comment = 1 ; }
[ ^ \ t \ n] { if (in_comment) is_comment = 1 ; else is_code = 1 ; } /* 非空格字符 */
\ n { /* 一行结束了,分析这行的属性 */
lineno ++ ;
if (!is_comment && !is_code)
emptylineno ++ ;
else
{
if (is_comment)
commentno ++ ;
if (is_code)
codeno ++ ;
}
is_comment = 0 ;
is_code = 0 ;
}
. { ; } /* 匹配漏掉的字符,使它不输出 */
%%
int main()
{
yylex();
/* 匹配最后一行 */
if (is_comment)
{
lineno ++ ;
commentno ++ ;
}
else if (is_code)
{
lineno ++ ;
codeno ++ ;
}
printf( " %d\t%d\t%d\t%d\n " , lineno, emptylineno, commentno, codeno);
return 0 ;
}
编译
D:\Work\lex>flex stat.c
D:\Work\lex>gcc -o statfile.exe lex.yy.c
D:\Work\lex>statfile < stat.c
46 3 15 39
这只是统计一个文件的程序,利用批处理实现统计当前目录包括子目录下的所有的*.c,*.cpp,*.h文件。
1 使用for /r %%a in (*.c *.h *.cpp) do @a.exe < %%a >>__tmp__.txt 命令枚举所有文件,把统计结输入到__tmp__.txt中。
2 使用add.exe把__tmp__.txt数据相加。
3 删除__tmp__.txt文件。
add.c文件:
/*
add.c
*/
#include < stdio.h >
int main()
{
int recv[ 4 ] ;
int res[ 4 ] = { 0 , 0 , 0 , 0 };
int i;
while ( 1 )
{
/* 读取数据 */
if (scanf( " %d\t%d\t%d\t%d " , recv,recv + 1 ,recv + 2 ,recv + 3 ) == EOF)
break;
for (i = 0 ; i < 4 ; i ++ )
res[i] += recv[i]; /* 数据相加 */
}
/* 输出结果 */
printf( " %d\t%d\t%d\t%d " , res[ 0 ], res[ 1 ], res[ 2 ], res[ 3 ]);
return 0 ;
}
#include < stdio.h >
int main()
{
int recv[ 4 ] ;
int res[ 4 ] = { 0 , 0 , 0 , 0 };
int i;
while ( 1 )
{
/* 读取数据 */
if (scanf( " %d\t%d\t%d\t%d " , recv,recv + 1 ,recv + 2 ,recv + 3 ) == EOF)
break;
for (i = 0 ; i < 4 ; i ++ )
res[i] += recv[i]; /* 数据相加 */
}
/* 输出结果 */
printf( " %d\t%d\t%d\t%d " , res[ 0 ], res[ 1 ], res[ 2 ], res[ 3 ]);
return 0 ;
}
编译 gcc -o add.exe add.c
stat.bat文件:
@
rem
stat.bat
@echo off
if " %1 " == " -f " goto file rem 统计单个文件
if " %1 " == " -h " goto help rem 帮助信息
if " %1 " == " -d " goto dir rem 统计当前目录下的文件
:dir
for / r %%a in ( * .c * .h * .cpp) do @statfile.exe < %%a >> __tmp__.txt
echo All Blank Comment Code
add.exe < __tmp__.txt
del __tmp__.txt
goto exit
:help
echo usage: [ - dfh][filename]
echo - d 统计当前目录和子目录所有的文件的代码注释
echo - f filename 统计该文件代码注释
echo - h 帮助
goto exit
:file
echo All Blank Comment Code
statfile.exe < % 2
goto : exit
: exit
echo on
@echo off
if " %1 " == " -f " goto file rem 统计单个文件
if " %1 " == " -h " goto help rem 帮助信息
if " %1 " == " -d " goto dir rem 统计当前目录下的文件
:dir
for / r %%a in ( * .c * .h * .cpp) do @statfile.exe < %%a >> __tmp__.txt
echo All Blank Comment Code
add.exe < __tmp__.txt
del __tmp__.txt
goto exit
:help
echo usage: [ - dfh][filename]
echo - d 统计当前目录和子目录所有的文件的代码注释
echo - f filename 统计该文件代码注释
echo - h 帮助
goto exit
:file
echo All Blank Comment Code
statfile.exe < % 2
goto : exit
: exit
echo on
现在可以运行stat.bat
D:\Work\lex>stat -h
usage: [-dfh][filename]
-d 统计当前目录和子目录所有的文件的代码注释
-f filename 统计该文件代码注释
-h 帮助
D:\Work\lex>stat -f stat.c
All Blank Comment Code
46 3 15 39
D:\Work\lex>stat -d
All Blank Comment Code
3026 580 547 1978
这个程序有一缺点,-d选项只能统计当前目录下的文件。