如上图 利用状态机的思想来解决C注释到C++注释的转换。(不允许注释嵌套)
在状态内处理,状态间跳转,根据不同的的事情发生相应的动作,并进行相应的状态转换。
程序共有四种状态 :NULSTATE(无状态),CSTATE(C状态),CPPSTATE(C++状态),ENDSTATE(结束状态)。
1.当为无状态时,遇到特定标记时进行状态转换,它有可能保持无状态,可能进入C状态,可能进入C++状态,也可能进入结束状态。
2.当为CPP状态时,遇到特定标记时进行状态转换,它有可能保持CPPSTATE(C++状态),可能进入NULSTATE(无状态),也可能进入ENDSTATE(结束状态)。
3.当为C状态时,遇到特定标记时进行状态转换,它有可能保持CSTATE(C状态),可能进入NULSTATE(无状态)。
4.当为结束状态时,转换束。
//CommentConvert.h
#ifndef __CommentConvert_H__
#define __CommentConvert_H__
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
typedef enum STATE
{
//结束状态
END_STATE,
//无状态
NUL_STATE,
//C状态
C_STATE,
//C++状态
CPP_STATE
}STATE;
//无状态处理
void DoNulState(FILE*pfIn, FILE*pfOut,STATE* state);
//C状态处理
void DoCState(FILE*pfIn, FILE*pfOut, STATE* state);
//C++状态处理
void DoCPPState(FILE*pfIn, FILE*pfOut, STATE* state);
#endif //__CommentConvert_H__
//CommentConvert.c
#include"CommentConvert.h"
void DoNulState(FILE*pfIn, FILE*pfOut,STATE *state)
{
int first = 0;
int second = 0;
first = fgetc(pfIn);
switch (first)
{
case '/'://如果取出的字符为‘/’说明有可能进入其他状态
{
//取出第二字符以确定状态是否需要转换
second = fgetc(pfIn);
switch (second)
{
case'/'://如果第二个字符是‘/’,进入C++状态
{
*state = CPP_STATE;
fputc(first, pfOut);
fputc(second, pfOut);
}
break;
case'*'://如果第二个字符是‘*’,进入C状态
{
*state = C_STATE;
fputc('/', pfOut);
fputc('/', pfOut);
}
break;
default://如果是其他字符,保持无状态
{
fputc(first, pfOut);
fputc(second, pfOut);
}
break;
}
}
break;
case EOF ://如果到达文件结尾,进入结束状态
{
*state = END_STATE;
}
break;
default://如果第一个字符是非‘/’字符则进行无状态处理
{
fputc(first, pfOut);
}
break;
}
}
void DoCPPState(FILE*pfIn, FILE*pfOut, STATE* state)
{
int first = 0;
first = fgetc(pfIn);
switch (first)
{
case'\n'://如果取出的第一个字符为‘\n’说明C++注释转换结束,进入无状态
{
*state = NUL_STATE;
fputc(first, pfOut);
}
break;
case EOF://如果到达文件结尾,进入结束状态
*state = END_STATE;
break;
default://如果第一个字符是非‘\n’,说明C++状态没有结束,字符进行C++状态处理
fputc(first, pfOut);
break;
}
}
void DoCState(FILE*pfIn, FILE*pfOut, STATE* state)
{
int first = 0;
int second = 0;
int third = 0;
first = fgetc(pfIn);
switch (first)
{
case '*'://如果取出的第一个字符为‘*’说明C状态可能要结束
{
second = fgetc(pfIn);
switch (second)
{
case'*'://如果取出的第二个字符为‘*’说明C状态没有结束
fputc(first, pfOut);
ungetc(second, pfIn);//把取出的第二个字符送回,以便下次读取
break;
case'/'://如果取出的第二个字符为‘/’说明C状态结束,进入无状态
*state = NUL_STATE;
third = fgetc(pfIn);
if (third == '\n')//判断这一行有没有结束
fputc(third, pfOut);
else//如果没有结束写入换行,并把读的第三字符送回
{
fputc('\n', pfOut);
ungetc(third, pfIn);
}
break;
default://如果是其他字符,字符进行C状态处理
{
fputc(first, pfOut);
fputc(second, pfOut);
}
break;
}
}
break;
case'\n'://进行C状态的多行注释处理
fputc(first, pfOut);
fputc('/', pfOut);
fputc('/', pfOut);
break;
default://如果是其他字符,字符进行C状态处理
{
fputc(first, pfOut);
}
break;
}
}
//test.c
#include"CommentConvert.h"
void CommentConvert(FILE*pfIn, FILE*pfOut)
{
STATE state = NUL_STATE;
while (state!=END_STATE)
{
switch (state)
{
case NUL_STATE://无状态
DoNulState(pfIn, pfOut, &state);
break;
case C_STATE://C状态
DoCState(pfIn, pfOut, &state);
break;
case CPP_STATE://C++状态
DoCPPState(pfIn, pfOut, &state);
break;
}
}
}
void test()
{
FILE*pfIn = fopen("input.c", "r");
FILE*pfOut = fopen("output.c", "w");
if (pfIn == NULL)
{
perror("open input.c");
exit(EXIT_FAILURE);
}
if (pfOut == NULL)
{
perror("open output");
fclose(pfIn);
exit(EXIT_FAILURE);
}
CommentConvert(pfIn, pfOut);
fclose(pfIn);
fclose(pfOut);
}
int main()
{
test();
return 0;
}
代码运行结果: