这个小项目是实现将c语言的注释风格转换为c++的注释风格,那么我们首先得明确它们的注释风格是什么。
c语言的注释风格是:/* */
c++的注释风格是://
首先分析一下我们在转换的时候应该有哪几种状态:
第一种NUL_State:空状态
第二种C_State: C语言状态
第三种CPP_State: C++状态
第四种END_State:结束状态
下来我们采用枚举的形式将其列出:
enum State
{
NUL_State,
C_State,
CPP_State,
END_State
};
在转换的过程中我们可以通过下图来加强理解:
图画的有点丑哈!!!
在这里注释转换操作的是文件,所以接下来我么采用文件操作。首先创建一个input.c用来存放未转化的c程序,再创建一个output.c用来存放注释转换后的代码。
首先我们要打开input.c文件,对这个文件的内容进行读取,然后处理,否则直接提示用户有错误; 接下来,我们还要打开output.c文件,对处理以后的代码进行写入。
下面先给出input.c,可能会出现的几种情况:
input.c
//1.一般情况
/*int i=0;*/
//2.换行问题
/*int i=0;*/ int j=0;
/*int i=0; */
//3.匹配问题
/* int i=0; /*xxxxx*/
//4.多行注释
/*
int i=c;
int j=c;
*/int k=c;
//5.连续注释问题
/**/**/
//6.连续的**/
/***/
//7.c++注释问题
// /*xxxxxxxxx*/
在项目中为了结构清晰, 通常我们采用封装文件的形式,CommentConvert.h封装头文件,test.c封装测试文件,CommentConvert.c封装函数.
下来我们就CommentConvert.c中的内容作进一步的分析:
(1)首先将初始状态置为NUL_State,当遇到 /* 时就将 // 写入output.c中,并进入C_State状态;如果出现 // 则直 接输出//即可,并进入到CPP_State状态;如果前两种情况都不是那么说明就是普通字符直接输出就行;如果 遇到EOF,那么就将状态置为END_State.
void Do_NUL_State(FILE *pfRead,FILE *pfWrite)
{
int first=0;
int second=0;
first=fgetc(pfRead); //fgetc函数的返回值为int型
switch(first)
{
case '/':
second=fgetc(pfRead);
if(second=='*')
{
fputc('/',pfWrite);
fputc('/',pfWrite);
state= C_State;
}
else if(second=='/')
{
fputc(first,pfWrite);
fputc(second,pfWrite);
state= CPP_State;
}
else
{
fputc(first,pfWrite);
fputc(second,pfWrite);
}
break;
case EOF:
state=END_State;
break;
default:
fputc(first,pfWrite);
break;
}
}
(2)在C_State中,如果出现*/(即第一个字符时*,第二个字符是/)则还需判定第三个字符:
如果没有遇到‘\n’,那么应该写入'\n'换到下一行,比如:/*int i=0;*/ int j=0;转换后应该是 //int i=0; (换行)int j=0;
如果又遇到 /, 那么就将第三个字符放入pfRead文件流里,并将状态置为NUL_State,继续循环;
如果两种情况都没遇到,那么直接输出第三个字符,并将状态置为NUL_State.
如果出现**(即连续读到的两个字符均为*) ,再判定第三个字符时 :
首先将第一个字符*放入文件流pfWrite中,第三个字符是 / 时那么就直接将状态置为NUL_State.比如:/***/,转换后应该是//*(*成为注释的内容);
第三个字符如果是其他情况就直接输出前两个字符即可.
如果遇到多行注释的问题:此时我们只需将'\n'直接写入output.c中并输出//即可,在c注释转换中如果我们将/*转换为//后,那么每行都得添加//
void Do_C_State(FILE *pfRead,FILE *pfWrite)
{
int first=0;
int second=0;
int third=0;
first=fgetc(pfRead);
switch(first)
{
case '*':
second=fgetc(pfRead);
switch(second)
{
case '/':
third=fgetc(pfRead);
if(third!='\n')
{
fputc('\n',pfWrite);
}
if(third=='/')
{
ungetc(third,pfRead); //将第三个字符放入input.c中
state= NUL_State;
break;
}
fputc(third,pfWrite); //将第三个字符写入output.c中
state= NUL_State;
break;
case '*':
third=fgetc(pfRead);
fputc(first,pfWrite); //将第一个*直接写入output.c中
if(third=='/')
{
state= NUL_State;
}
break;
default:
fputc(first,pfWrite);
fputc(second,pfWrite);
break;
}
break;
case '\n':
fputc(first,pfWrite);
fputc('/',pfWrite);
fputc('/',pfWrite);
break;
case EOF:
state=END_State;
break;
default:
fputc(first,pfWrite);
break;
}
}
(3)在CPP_State中,遇到\n就直接将状态置为NUL_State; 遇到EOF将状态置为END_State;遇到其他字符按照普通字符直接输出即可。
void Do_Cpp_State(FILE *pfRead,FILE *pfWrite)
{
int first=0;
first=fgetc(pfRead);
switch(first)
{
case '\n':
fputc(first,pfWrite);
state= NUL_State;
break;
case EOF:
state=END_State;
break;
default:
fputc(first,pfWrite);
break;
}
}
下面给出完整代码:
CommentConvert.h
#ifndef _CommentConvert_
#define _CommentConvert_
#include<stdio.h>
#include<stdlib.h>
#define INPUTFILENAME "input.c"
#define OUTPUTFILENAME "output.c"
enum State
{
NUL_State,
C_State,
CPP_State,
END_State
};
void CommentConvert(FILE *pfRead,FILE *pfWrite);
void Do_NUL_State(FILE *pfRead,FILE *pfWrite);
void Do_C_State(FILE *pfRead,FILE *pfWrite);
void Do_Cpp_State(FILE *pfRead,FILE *pfWrite);
#endif
Test.c
#include "CommentConvert.h"
int main()
{
FILE *pfRead=NULL;
FILE *pfWrite=NULL;
printf("转换开始:\n");
pfRead=fopen(INPUTFILENAME,"r");
if(NULL==pfRead)
{
perror("fopen file for read" );
exit(EXIT_FAILURE);
}
pfWrite=fopen(OUTPUTFILENAME,"w");
if(NULL==pfRead)
{
fclose(pfRead);
perror("fopen file for write" );
exit(EXIT_FAILURE);
}
CommentConvert(pfRead,pfWrite);
printf("转换结束!");
fclose(pfRead);
fclose(pfWrite);
system("pause");
return 0;
}
CommentConvert.c
#include "CommentConvert.h"
enum State state=NUL_State;
void CommentConvert(FILE *pfRead,FILE *pfWrite)
{
while(state!=END_State)
{
switch (state)
{
case NUL_State:
Do_NUL_State(pfRead,pfWrite);
break;
case C_State:
Do_C_State(pfRead,pfWrite);
break;
case CPP_State:
Do_Cpp_State(pfRead,pfWrite);
break;
case END_State:
break;
}
}
}
void Do_NUL_State(FILE *pfRead,FILE *pfWrite)
{
int first=0;
int second=0;
first=fgetc(pfRead); //fgetc函数的返回值为int型
switch(first)
{
case '/':
second=fgetc(pfRead);
if(second=='*')
{
fputc('/',pfWrite);
fputc('/',pfWrite);
state= C_State;
}
else if(second=='/')
{
fputc(first,pfWrite);
fputc(second,pfWrite);
state= CPP_State;
}
else
{
fputc(first,pfWrite);
fputc(second,pfWrite);
}
break;
case EOF:
state=END_State;
break;
default:
fputc(first,pfWrite);
break;
}
}
void Do_C_State(FILE *pfRead,FILE *pfWrite)
{
int first=0;
int second=0;
int third=0;
first=fgetc(pfRead);
switch(first)
{
case '*':
second=fgetc(pfRead);
switch(second)
{
case '/':
third=fgetc(pfRead);
if(third!='\n')
{
fputc('\n',pfWrite);
}
if(third=='/')
{
ungetc(third,pfRead); //将第三个字符放入input.c中
state= NUL_State;
break;
}
fputc(third,pfWrite); //将第三个字符写入output.c中
state= NUL_State;
break;
case '*':
third=fgetc(pfRead);
fputc(first,pfWrite); //将第一个*直接写入output.c中
if(third=='/')
{
state= NUL_State;
}
break;
default:
fputc(first,pfWrite);
fputc(second,pfWrite);
break;
}
break;
case '\n':
fputc(first,pfWrite);
fputc('/',pfWrite);
fputc('/',pfWrite);
break;
case EOF:
state=END_State;
break;
default:
fputc(first,pfWrite);
break;
}
}
void Do_Cpp_State(FILE *pfRead,FILE *pfWrite)
{
int first=0;
first=fgetc(pfRead);
switch(first)
{
case '\n':
fputc(first,pfWrite);
state= NUL_State;
break;
case EOF:
state=END_State;
break;
default:
fputc(first,pfWrite);
break;
}
}