首先来看如下C注释状态的测试用例:
// 1.一般情况
/* int i = 0; */
// 2.换行问题
/* int i = 0; */int j = 0;
/* int i = 0; */
int j = 0;
// 3.匹配问题
/*int i = 0;/*xxxxx*/
// 4.多行注释问题
/*
int i=0;
int j = 0;
int k = 0;
*/int k = 0;
// 5.连续注释问题
/**//**/
// 6.连续的**/问题
/***/
// 7.C++注释问题
// /*xxxxxxxxxxxx*/
转换为C++注释状态后:
// 1.一般情况
// int i = 0;
// 2.换行问题
// int i = 0;
int j = 0;
// int i = 0;
int j = 0;
// 3.匹配问题
//int i = 0;/*xxxxx
// 4.多行注释问题
//
//int i=0;
//int j = 0;
//int k = 0;
//
int k = 0;
// 5.连续注释问题
//
//
// 6.连续的**/问题
//*
// 7.C++注释问题
// /*xxxxxxxxxxxx*/
现在来分析如何转换,先设定C注释的文件夹名为input,装换为C++注释的文件夹名为output,并且设置三个全局变量first,second,third用来记录读取到的连续的三个字符,一个全局变量state记录当前的注释状态,初值为空状态。
0 .对于本身就是C++注释状态,判断是C++注释状态的条件为读取到的两个连续字符都为‘/’,此时向output文件中输入两个字符‘/’,并且,将state赋值为C++的状态。继续从input文件中读取字符,若读到换行符‘\n’,则将换行符输入到output文本中,将state赋值为空状态,代表此时已经完成一行注释,接着开始新的注释装换;若为文件尾,则state赋值为文件尾标志,否则代表读取到的都为注释状态,应跟在开始输入的“//”后面。代码如下:
void DoCPP_State(FILE *pfread, FILE *pfwrite)
{
first = fgetc(pfread);
switch (first)
{
case '\n':
fputc('\n', pfwrite);
state = NUL_State;
break;
case EOF:
state = END_State;
break;
default:
fputc(first, pfwrite);
break;
}
}
1.对于第一种最一般的情况,一行只有一个C的注释状态,判断条件为first==‘/’,second==‘* ’,此时向文件中输入两个‘/’字符,并将state赋值为C的注释状态,接下来进行C的注释状态结束判断。结束条件为first==‘*’,second==‘/’,此时将state赋值为空状态,代表此时已经完成一行注释,接着开始新的注释装换。
2.对于第二种换行问题,当读取到C的注释状态结束时,应该继续读取下一个字符,赋值给third,此时third的值应该是非注释内容,应该换行并且将内容输入到output文件中。
3.对于第三种匹配问题,当确认为C的注释转态后,只有当first==‘* ’,second==‘/’时才认为注释结束,需要排除注释内容有字符‘*’和‘/’的情况。
4.后面的情况为前几种情况的综合。
处理代码如下:
void DoC_State(FILE *pfread, FILE *pfwrite)
{
assert(pfread);
assert(pfwrite);
first = fgetc(pfread);
switch (first)
{
case '*':
second = fgetc(pfread);
switch (second)
{
case '/':
third = fgetc(pfread);
if (third == '/') //连续注释的状态,如:/*xxx*//*xxx*/
{
fputc('\n', pfwrite);
ungetc(third, pfread);
state = NUL_State;
break;
}
state = NUL_State;
if (third != '\n')
{
fputc('\n', pfwrite);
}
fputc(third, pfwrite);
break;
case '*': //注释中有“*”,如/***/
third = fgetc(pfread);
fputc(first, pfwrite);//把“*”输入到转换后的文件流中
if (third == '/') //C注释后面紧跟非注释内容,如/***/ int=a;
fputc('\n', pfwrite);
state = NUL_State;
break;
default: //不是注释的字符
fputc(first, pfwrite);
fputc(second, pfwrite);
break;
}
break;
case '\n': //C注释中的多行注释
fputc('\n', pfwrite);
fputc('/', pfwrite);
fputc('/', pfwrite);
break;
case EOF: //文件结束标志
state = END_State;
break;
default: //不是注释的字符
fputc(first, pfwrite);
break;
}
}
完整代码如下:
CommentConvert.h
#ifndef __COMMENTCONVERT_H__
#define __COMMENTCONVERT_H__
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdlib.h>
#include<assert.h>
#include<stdio.h>
#define INPUT "input.c"
#define OUTPUT "output.c"
enum STATE
{
NUL_State,
C_State,
CPP_State,
END_State
};
void DoCommentConvert(FILE *pfread, FILE *pfwrite);
void DoNUL_State(FILE *pfread, FILE *pfwrite);
void DoC_State(FILE *pfread, FILE *pfwrite);
void DoCPP_State(FILE *pfread, FILE *pfwrite);
#endif //__COMMENTCONVERT_H__
main.c
#include"CommentConvert.h"
int main()
{
FILE *pfread = fopen(INPUT, "r");
if (NULL == pfread)
{
perror("open file for read");
exit(EXIT_FAILURE);
}
FILE *pfwrite = fopen(OUTPUT, "w");
if (NULL == pfwrite)
{
fclose(pfread);
perror("open file for write");
exit(EXIT_FAILURE);
}
DoCommentConvert(pfread, pfwrite);
fclose(pfread);
fclose(pfwrite);
return 0;
}
CommentConvert.c
#include"CommentConvert.h"
enum STATE state = NUL_State; //设最开始是空状态
char first = 0;
char second = 0;
char third = 0;
void DoCommentConvert(FILE *pfread, FILE *pfwrite)
{
while (state != END_State)
{
switch (state)
{
case NUL_State:
DoNUL_State(pfread, pfwrite);
break;
case C_State:
DoC_State(pfread, pfwrite);
break;
case CPP_State:
DoCPP_State(pfread, pfwrite);
break;
case END_State:
break;
default:
break;
}
}
}
void DoNUL_State(FILE *pfread, FILE *pfwrite)
{
assert(pfread);
assert(pfwrite);
first = fgetc(pfread); //从文件中读取一个字符
switch (first)
{
case '/':
second = fgetc(pfread);
if (second == '*')
{
fputc('/', pfwrite);
fputc('/', pfwrite);
state = C_State; //代表此时为C状态
}
else if (second == '/') //说明此时本来就是C++注释的状态
{
fputc(first, pfwrite);
fputc(second, pfwrite);
state = CPP_State;
}
else
{
fputc(first, pfwrite); //说明此时非注释状态
fputc(second, pfwrite);
}
break;
case '\n':
fputc('\n', pfwrite);
break;
case EOF:
state = END_State;
break;
default:
fputc(first, pfwrite);
break;
}
}
void DoC_State(FILE *pfread, FILE *pfwrite)
{
assert(pfread);
assert(pfwrite);
first = fgetc(pfread);
switch (first)
{
case '*':
second = fgetc(pfread);
switch (second)
{
case '/':
third = fgetc(pfread);
if (third == '/') //连续注释的状态,如:/*xxx*//*xxx*/
{
fputc('\n', pfwrite);
ungetc(third, pfread);
state = NUL_State;
break;
}
state = NUL_State;
if (third != '\n')
{
fputc('\n', pfwrite);
}
fputc(third, pfwrite);
break;
case '*': //注释中有“*”,如/***/
third = fgetc(pfread);
fputc(first, pfwrite);//把“*”输入到转换后的文件流中
if (third == '/') //C注释后面紧跟非注释内容,如/***/ int=a;
fputc('\n', pfwrite);
state = NUL_State;
break;
default: //不是注释的字符
fputc(first, pfwrite);
fputc(second, pfwrite);
break;
}
break;
case '\n': //C注释中的多行注释
fputc('\n', pfwrite);
fputc('/', pfwrite);
fputc('/', pfwrite);
break;
case EOF: //文件结束标志
state = END_State;
break;
default: //不是注释的字符
fputc(first, pfwrite);
break;
}
}
void DoCPP_State(FILE *pfread, FILE *pfwrite)
{
first = fgetc(pfread);
switch (first)
{
case '\n':
fputc('\n', pfwrite);
state = NUL_State;
break;
case EOF:
state = END_State;
break;
default:
fputc(first, pfwrite);
break;
}
}