什么是注释转换?
注释转换就是将C语言里面的注释转换成C++风格注释,我们将用有限状态机模型来处理该项目。
什么是有限状态机?
有限状态机FSM是软件上常⽤的⼀种处理⽅法,它把复杂的控制逻辑分解成有限个稳定状态,在每个状态上进⾏处理。 有限状态机是闭环系统,可以⽤有限的状态,处理⽆穷的事务。
通常我们使⽤多路分之语句来处理状态机
switch (state)
{
case 1:
break;
case 2:
break;
case 3:
break;
...
case n:
break;
default:
break;
}
了解了处理方法之后,我们来看一下c/c++注释转换的模型:
其中,左边的图表示,将c语言注释的代码放在input.c文件中,然后将注释转换后的c++风格的代码放在output.c中。
我们先将input.c给出来:
// 1.一般情况
/* int i = 0; */
// 2.换行问题
/* int i = 0; */int j = 0;
/* int i = 0; */
int m = 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语言状态,NULL状态,CPP状态,END状态。
假设刚一开始处于NULL状态,然后从input.c中读字符,进行处理时有以下几种情况:
(1)当遇到“/*”时,就进入C状态;
(2)遇到“//”时进入CPP状态;
(3)遇到文件结束标志EOF时,进入END状态;
(4)其余情况直接写入output.c即可。
分析清楚之后,我们给出NULL状态时的转换函数:
void NULL_convert_(FILE *pread, FILE *pwrite)
{
first = fgetc(pread);//先读取第一个字符
switch (first)
{
case'/'://如果第一个字符是‘/’,则需要判断第二个字符
{
second = fgetc(pread);//读取第二个字符
if ('*' == second)//如果第二个字符是‘*’,则将‘//’写入,并转换为C状态
{
fputc(first, pwrite);
fputc('/', pwrite);
state = C_convert;
}
else if ('/' == second)//如果第二个字符是‘/’,则将读取到的两个字符写入,并转换为CPP状态
{
fputc(first, pwrite);
fputc(second, pwrite);
state = CPP_convert;
}
else//如果是其他情况,则直接写入即可
{
fputc(first, pwrite);
fputc(second, pwrite);
}
}
break;
case EOF://遇到文件结束标志,直接进入结束状态
state = END_convert;
break;
default:
fputc(first, pwrite);
break;
}
}
进入C状态时,从input.c中读到字符之后有以下几种状况:
(1)读到文件结束标志EOF时,直接进入END状态;
(2)当读到“\n”时,将“\n”写入,同时将“//”写入output.c中;
(3)当读到“*/”时,需要再向后读一个字符并分三种情况处理:
a、“*/”后面无其他字符,则不需要处理直接进入NULL状态;
b、“*/”后面又读到一个“/”,则需要向input.c中写入一个“/”,并进入NULL状态即可;
c、“*/”后面读到一个”\n”,则将“\n”写入即可。
(4)当读到“*”时,则将第一个“”写入,再判断第三个字符,如果第三个字符是“/”,则将进入NULL状态即可;
(5)其他情况直接将读到的字符写入output.c即可。
下面给出C语言状态时的转换:
void C_convert_(FILE *pread, FILE *pwrite)
{
first = fgetc(pread);
switch (first)
{
case '*':
second = fgetc(pread);
switch (second)
{
case '*':
third = fgetc(pread);
fputc(first, pwrite);
if ('/'== third)
{
state = NULL_convert;
}
break;
case '/':
third = fgetc(pread);
if (third != '\n') // /* int i = 0; */int j = 0;
{
fputc('\n', pwrite);
}
if (third == '/') //5.连续的注释问题/**//**/
{
ungetc('/', pread);
state = NULL_convert;
break;
}
fputc(third, pwrite); // /* int i = 0; */ \n int j = 0;
state = NULL_convert;
break;
default:
fputc(first, pwrite);
fputc(second, pwrite);
break;
}
break;
case '\n':
fputc('\n', pwrite);
fputc('/', pwrite);
fputc('/', pwrite);
break;
case EOF:
state = END_convert;
break;
default:
fputc(first, pwrite);
break;
}
}
进入CPP状态时,读到字符后有三种情况需要处理:
(1)读到文件结束标志EOF时,直接进入END状态;
(2)读到字符“\n”时,将“\n”写入output.c中,然后进入NULL状态;
(3)读到其他字符直接写入output.c中即可。
下面是CPP状态时的转换:
void CPP_convert_(FILE *pread, FILE *pwrite)
{
first = fgetc(pread);
switch (first)
{
case'\n'://如果是'\n'写入,再转换为无状态
{
fputc(first, pwrite);
state = NULL_convert;
}
break;
case EOF://如果遇到EOF,则直接进去结束状态
state = END_convert;
break;
default:
fputc(first, pwrite);
break;
}
}
所有的状态之间的转换至此已将全部分析完了,当然还需要一个函数来完成各种状态之间的转换:
void CommentConvert(FILE *pread, FILE *pwrite)
{
state = NULL_convert;//刚开始处于无状态
while (state!=END_convert)
{
switch (state)
{
case NULL_convert:
NULL_convert_(pread, pwrite);
break;
case C_convert:
C_convert_(pread, pwrite);
break;
case CPP_convert:
CPP_convert_(pread, pwrite);
break;
}
}
}
接下来给出该项目的源码:
头文件部分:
#define _CRT_SECURE_NO_WARNINGS 1
#ifndef __ZHUSHICONVERT_H__
#define __ZHUSHICONVERT_H__
#include <stdio.h>
enum STATE
{
NULL_convert,
C_convert,
CPP_convert,
END_convert
};
void NULL_convert_(FILE *pread, FILE *pwrite);
void C_convert_(FILE *pread, FILE *pwrite);
void CPP_convert_(FILE *pread, FILE *pwrite);
void CommentConvert(FILE *pread, FILE *pwrite);
#endif // zhushiconvert.h
各个函数的实现:
#include "zhushiconvert.h"
enum STATE state = NULL_convert;
int first = 0;
int second = 0;
int third = 0;
void NULL_convert_(FILE *pread, FILE *pwrite)
{
first = fgetc(pread);//先读取第一个字符
switch (first)
{
case'/'://如果第一个字符是‘/’,则需要判断第二个字符
{
second = fgetc(pread);//读取第二个字符
if ('*' == second)//如果第二个字符是‘*’,则将‘//’写入,并转换为C状态
{
fputc(first, pwrite);
fputc('/', pwrite);
state = C_convert;
}
else if ('/' == second)//如果第二个字符是‘/’,则将读取到的两个字符写入,并转换为CPP状态
{
fputc(first, pwrite);
fputc(second, pwrite);
state = CPP_convert;
}
else//如果是其他情况,则直接写入即可
{
fputc(first, pwrite);
fputc(second, pwrite);
}
}
break;
case EOF://遇到文件结束标志,直接进入结束状态
state = END_convert;
break;
default:
fputc(first, pwrite);
break;
}
}
void C_convert_(FILE *pread, FILE *pwrite)
{
first = fgetc(pread);
switch (first)
{
case '*':
second = fgetc(pread);
switch (second)
{
case '*':
third = fgetc(pread);
fputc(first, pwrite);
if ('/'== third)
{
state = NULL_convert;
}
break;
case '/':
third = fgetc(pread);
if (third != '\n') // /* int i = 0; */int j = 0;
{
fputc('\n', pwrite);
}
if (third == '/') //5.连续的注释问题/**//**/
{
ungetc('/', pread);
state = NULL_convert;
break;
}
fputc(third, pwrite); // /* int i = 0; */ \n int j = 0;
state = NULL_convert;
break;
default:
fputc(first, pwrite);
fputc(second, pwrite);
break;
}
break;
case '\n':
fputc('\n', pwrite);
fputc('/', pwrite);
fputc('/', pwrite);
break;
case EOF:
state = END_convert;
break;
default:
fputc(first, pwrite);
break;
}
}
void CPP_convert_(FILE *pread, FILE *pwrite)
{
first = fgetc(pread);
switch (first)
{
case'\n'://如果是'\n'写入,再转换为无状态
{
fputc(first, pwrite);
state = NULL_convert;
}
break;
case EOF://如果遇到EOF,则直接进去结束状态
state = END_convert;
break;
default:
fputc(first, pwrite);
break;
}
}
void CommentConvert(FILE *pread, FILE *pwrite)
{
state = NULL_convert;//刚开始处于无状态
while (state!=END_convert)
{
switch (state)
{
case NULL_convert:
NULL_convert_(pread, pwrite);
break;
case C_convert:
C_convert_(pread, pwrite);
break;
case CPP_convert:
CPP_convert_(pread, pwrite);
break;
}
}
}
测试部分:
#include "zhushiconvert.h"
#include <stdlib.h>
int main()
{
FILE *pread = NULL;
FILE *pwrite = NULL;
pread = fopen("input.c", "r");
if (NULL == pread)
{
perror("file to read");
exit(EXIT_FAILURE);
}
pwrite = fopen("output.c","w");
if (NULL == pwrite)
{
fclose(pread);
perror("file to write");
exit(EXIT_FAILURE);
}
CommentConvert(pread, pwrite);
fclose(pread);
fclose(pwrite);
return 0;
}
最后来看一下output.c文件里面的内容是不是跟我们预想的一样呢?
// 1.一般情况
// int i = 0;
// 2.换行问题
// int i = 0;
int j = 0;
// int i = 0;
int m = 0;
// 3.匹配问题
//int i = 0;/*xxxxx
// 4.多行注释问题
//
//int i=0;
//int j = 0;
//int k = 0;
//
int k = 0;
// 5.连续注释问题
//
//
// 6.连续的**/问题
//*
// 7.C++注释问题
// /*xxxxxxxxxxxx*/