1 需求分析
1) 问题描述: 读入一个(最多9个)C程序代码文件,统计程序中代码、注释和空行数以及函数的个数,显示函数名并生成相应的记录日志。
2) 基本要求如下:
(1)、把程序文件(如.c或者.txt等)按字符顺序读入源程序;
(2)、输入正确性检查;
(3)、边读入程序,边识别统计代码行、注释行和空行,同时还要识别函数,统计代码个数;
(4)、最多允许一次分析9个文件
2 显示结果
备注:本文的代码试验IDE为VS2013。本代码对比较常规的编程习惯下编写的C代码可以比较好的识别,但是对一些特殊情况不能识别。
1) 问题描述: 读入一个(最多9个)C程序代码文件,统计程序中代码、注释和空行数以及函数的个数,显示函数名并生成相应的记录日志。
2) 基本要求如下:
(1)、把程序文件(如.c或者.txt等)按字符顺序读入源程序;
(2)、输入正确性检查;
(3)、边读入程序,边识别统计代码行、注释行和空行,同时还要识别函数,统计代码个数;
(4)、最多允许一次分析9个文件
2 显示结果
备注:本文的代码试验IDE为VS2013。本代码对比较常规的编程习惯下编写的C代码可以比较好的识别,但是对一些特殊情况不能识别。
1)输入正确的文件个数和路径
2)输入正确时生成的日志文件
3 程序结构
1)整体结构
2)分析模块结构
4 源代码
整个工程共有三个文件构成:statist.h;source.c;main.c
1) statist.h
#define SIZE_N 100
#define SIZE_L 200
#define NUM_F 9
#define title "------------------------Life is a Fight-----------------------------------"
extern bool com_flag;
void getline(FILE* pfile, char* pt);
char* clearblank(char*pt);
char* mystrstr(char* s1, char* s2);
bool Isblank(char* pt);
int Iscom(char* pt);
bool Isfunc(char* pt);
bool Qtycheck(int* pt);
2) source.c
#include<stdio.h>
#include<string.h>
#include<stdbool.h>
#include"statist.h"
void getline(FILE* pfile,char* pt)
{
while (!feof(pfile))
{
*pt = fgetc(pfile);
if (*pt=='\n') //成功读取完一行,直到换行符
{
*pt = '\0';
return;
}
pt++;
}
*pt = '\0'; //如果还没有检测到换行符,文件已经结束,则在末尾添加终止符
}
char* clearblank(char* pt)
{
while ((*pt == ' ') || (*pt == ' '))
{
pt++;
}
return pt;
}
char* mystrstr(char* s1, char* s2)
{
char*s, *sp1, *temp1, *temp2;
int q_flag = 0;
if (strstr(s1, "\"") == NULL) //如果没有发现引号
{
s = strstr(s1, s2);
return s;
}
else //如果发现引号
{
sp1 = s1;
while (*sp1)
{
temp1 = strstr(sp1, "\"");
temp2 = strstr(sp1, s2);
if ((temp1 != NULL) && (temp1 == sp1))
{
if (q_flag == 0)
q_flag = 1;
else
q_flag = 0;
}
if ((temp2 != NULL) && (q_flag == 0) && (temp2 == sp1))
return sp1;
sp1++;
}
return NULL;
}
}
bool Isblank(char* pt)
{
clearblank(pt);
if (*pt == '\0')
return 1;
return 0;
}
int Iscom(char* pt)
{
char* pt1,*pt2,*pt3;
clearblank(pt);
pt1 = mystrstr(pt, "//");
pt2 = mystrstr(pt, "/*");
pt3 = mystrstr(pt, "*/");
if (com_flag == 0)
{
if ((pt2!=NULL) && (pt3 == NULL)) //如果只有/*表明注释开始
com_flag = 1;
if (pt1 == pt) //双斜杠开头的注释
return 1;
else if (pt1 - pt > 0 || pt2 - pt > 0) //有注释符号,但是不是顶头开始
return 2;
else if ((pt2 == pt) && ((pt3 != NULL && (*(pt3 + 2) == '\0')) || (pt3 == NULL))) //以/*开头以*/结尾,或者以/*开头,没有检测到*/
return 1;
else if ((pt2 == pt) && (pt3 != NULL) && (*(pt3 + 2) != '\0')) //以/*开头但是没有以*/结尾
return 2;
else if (pt1 == NULL || pt2 == NULL) //没有检测到注释符号
return 0;
}
else if (com_flag == 1)
{
if (pt3!=NULL)
{
com_flag = 0;
return 1;
}
printf("\nYYYY\n");
return 1; //如果com_flag==1,且没有检测到*/则是一句注释
}
}
bool Isfunc(char* pt)
{
char* pt1, *pt2, *pt3,*pt4,*pt5,*pt6;
clearblank(pt);
pt1 = mystrstr(pt, "(");
pt2 = mystrstr(pt, ";");
pt3 = mystrstr(pt, "if");
pt4 = mystrstr(pt, "while");
pt5 = mystrstr(pt, "for");
pt6 = mystrstr(pt, "switch");
if (pt1 != NULL&&pt2 == NULL&&pt3 == NULL&&pt4 == NULL&&pt5 == NULL&&pt6 == NULL)
return true;
return false;
}
bool Qtycheck(int* pt)//只允许输入一个1到9的数字
{
char temp[3];
char c;
fflush(stdin);
gets(temp);
if (temp[0]>'0'&&temp[0] <= '9'&&temp[1] == '\0')
*pt = (int)(temp[0] - 48);
else
{
fflush(stdin);
printf("Please re-enter the file quantity(0<n<10):");
return 0;
}
return 1;
}
3) main.c
#include<stdio.h>
#include<string.h>
#include<stdbool.h>
#include"statist.h"
#include<stdlib.h>//system()的头文件
#include<malloc.h>
bool com_flag;
int main(void)
{
FILE* in,*log;
char con;
char temp[SIZE_L + 1];
char name[SIZE_N];
char* pt;
char* name_t;
int* result;
int n = 0;
struct FIL{
int cod;
int blk;
int com;
int fct;
}fil = { 0, 0, 0, 0 };
com_flag = 0;
do{
printf("%s", title);
printf("\n\n\nPlease enter the file quantity(0<n<10):");
while (!Qtycheck(&n));
name_t = (char*)malloc(n*sizeof(name));
result = (int*)malloc(n * 4 * sizeof(int));
log = fopen("log.txt", "w");
fprintf(log, "%s\n\n\n", title);
for (int i = 0; i < n; i++)
{
printf("please enter file \"%d\" name:", i + 1);
scanf("%s", name_t + i*SIZE_N);
in = fopen(name_t + i*SIZE_N, "r");
while (!in)
{
fflush(stdin);
printf("please re-enter file \"%d\" name:", i + 1);
scanf("%s", name_t + i*SIZE_N);
in = fopen(name_t + i*SIZE_N, "r");
}
fclose(in);
}
for (int i = 0; i < n; i++)
{
in = fopen(name_t + i*SIZE_N, "r");
while (!feof(in))
{
getline(in, temp);
pt = clearblank(temp);
if (Isblank(pt) == 1 && com_flag == 0)
{
fil.blk++;
continue;
}
else if (Iscom(pt) == 1)
{
fil.com++;
continue;
}
else if (Iscom(pt) == 2 && Isfunc(pt) == 0)
fil.com++;
else if (Iscom(pt) == 2 && Isfunc(pt) == 1)
{
fil.com++;
fil.fct++;
fil.cod++;
fprintf(log, "%s %s\n", name_t + i*SIZE_N, temp);
continue;
}
else if (Isfunc(pt) == 1)
{
fil.fct++;
fprintf(log, "%s %s\n", name_t + i*SIZE_N, temp);
}
fil.cod++;
}
*(result + 4 * i) = fil.blk;
*(result + 4 * i + 1) = fil.cod;
*(result + 4 * i + 2) = fil.com;
*(result + 4 * i + 3) = fil.fct;
fil.blk = 0;
fil.cod = 0;
fil.com = 0;
fil.fct = 0;
com_flag = 0;
fclose(in);
if (fil.fct)
fprintf(log, "\n\n\n");
}
fprintf(log, "%s", "\n\n\n==========================================================");
printf("==========================================================");
printf("\nFile No. Blank Code Commen Function\n");
fprintf(log, "\n%s\n", "File No. Blank Code Commen Function");
for (int i = 0; i < n; i++)
{
printf("%d %d %d %d %d\n", i + 1, *(result + 4 * i), *(result + 4 * i + 1), *(result + 4 * i + 2), *(result + 4 * i + 3));
fprintf(log, "%d %d %d %d %d\n", i + 1, *(result + 4 * i), *(result + 4 * i + 1), *(result + 4 * i + 2), *(result + 4 * i + 3));
}
fclose(log);
free(name_t);
free(result);
printf("\n\n\nPress 'Y' to continue\n");
fflush(stdin);
con = getchar();
printf("\n\n\n");
} while (con=='Y'||con=='y');
system("pause");
return 0;
}