项目之注释转换

本次项目为注释转换。要求为:将一个文件中的所有注释(/**/、//)均转换为C++注释(//)到另一个文件。

整体思路:

1.首先,提到文件那么就需要进行打开文件读取文件写入文件关闭文件等这些操作,我们可以将需要进行注释转换的文件称为源文件,而将转换后的新文件称为目标文件。那么,此时就相当于将源文件通过编写关于注释转换的程序生成目标文件。

既然源数据是文件类型,就需要我们在程序中读取文件中的内容,可以通过字符的形式读取。那么在处理这些文件的打开读取写入关闭等操作中可能需要用到的函数有:

(1)打开文件的函数:fopen()

(2)按字符读取的函数:fgetc()

(3)按字符写入的函数:fputc()

(4)关闭文件的函数:fclose()

2.既然是注释到注释之间的转换,那么具体有哪些注释转换的情况呢?假设如下就是源文件的内容:

// 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*/

我们可以将这些在注释转换中可能出现的情况进行梳理归纳:

既然以字符的形式读取和写入文件内容,就需要将读取出来的内容进行判断。当读取出的内容为'/'时应该怎么处理,当读取出的内容为'*'时应该怎么处理等等,根据分析情况,可以归纳出五种状态,那么下面我将通过画图归纳出这五种状态分别是什么以及它们之间状态转换的关系:


现在知道了这五种状态以及它们之间的转换,那么在状态进行转换时应该进行怎样的操作呢?下面具体说明:

1.当在普通状态下时

(1)当源文件中取出'/'时,则将'/'写入目标文件并且状态变为遇到'/'状态。

(2)当源文件取出其他字符时,则直接将该字符写入到目标文件并且状态仍为普通状态。

2.当在遇到'/'状态下时

(1)当源文件取出'*'时,则表示为C注释,需要转换为C++注释,故将'/'写入目标文件并且状态变为C注释状态。

(2)当源文件取出'/'时,则表示为C++注释,故直接将'/'写入到目标文件并且状态变为C++注释状态。

(3)当源文件取出其他字符时,表示不是注释语句,故直接写入到目标文件并且状态变为普通状态。

3. 当在C++注释状态时

(1)当源文件取出'\n'时,则直接将'\n'写入目标文件并且状态变为普通状态。

(2)当源文件取出其他字符时,则直接将其写入目标文件并且状态仍为C++注释状态。

4.当在C注释状态时

(1)当源文件取出'*'时:

①再次读取源文件当取出为'*'时,则将第一次读取到的'*'写入目标文件并且状态变为遇到'*'状态。

②再次读取源文件当取出为'/'时,则将第二次取出的字符还回源文件并且状态变为遇到'*'状态。

③再次读取源文件当取出为其他字符时,则将取出的'*'以及第二次取出的字符均写入目标文件并且状态仍为C注释状态。

(2)当源文件取出'\n'时,此时需要换行并且仍然在C注释中,故下一行仍然为注释语句,故需要将'\n'和'/'和'/'写入目标文件并且状态仍然为C注释状态。

(3)当源文件取出其他字符时,则直接将其写入到目标文件并且状态仍为C注释状态。

5.当在遇到'*'状态时

(1)当源文件取出'*'时,则直接将'*'写入到目标文件并且状态仍然为遇到'*'状态。

(2)当源文件取出'/'时,表示C注释结束:

①则再次读取源文件当取出为'\n'时则直接将第二次读取到的'\n'写入到目标文件并且状态变为普通状态。

②则再次读取源文件当取出不是'\n'时则需要自己将'\n'写入到目标文件并且将第二次读取到的字符返还给源文件(使用ungetc()函数),状态变为普通状态。

(3)当源文件取出其他字符时,则直接将其写入到目标文件并且状态变为C注释状态。

3.根据以上思路编写代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<Windows.h>
#include<stdio.h>
#include<stdlib.h>
//定义枚举类型,用于表示有限的5个状态
typedef enum State{
	NORMAL,       //普通状态
	FOUND_SLASH,  //遇到/状态
	CPP_COMMENT,  //c++注释状态
	C_COMMENT,    //c注释状态  
	FOUND_STAR,  //遇到*状态
}State;
//main函数
int main()
{
	//打开源文件以及目标文件
	FILE* inputFile = fopen("C:\\Users\\Administrator\\Desktop\\input.c", "r");
	FILE* outputFile = fopen("C:\\Users\\Administrator\\Desktop\\output.c", "w");
	//判断源文件是否为NULL,若为NULL则直接return 0
	if (inputFile == NULL)
	{
		goto CLOSE_FILE1;
	}
	//判断目标文件是否为NULL,若为NULL则关闭源文件
	if (outputFile == NULL)
	{
		goto CLOSE_FILE2;
	}
	//CommentConvert()方法用于进行源文件到目标文件的注释转换的操作
	CommentConvert(inputFile, outputFile);
	//操作完毕关闭目标文件
	fclose(outputFile);
CLOSE_FILE2:
	//操作完毕关闭源文件
	fclose(inputFile);
CLOSE_FILE1:
	system("pause");
	return 0;
}
void CommentConvert(FILE* input, FILE* output)
{
	State state = NORMAL;
	int ch = 0;
	int next = 0;
	while (1)
	{
		//读取源文件
		ch = fgetc(input);
		if (ch == EOF)
		{
			return;
		}
		//进入状态并进行相关操作
		switch (state)
		{
		//1.当在普通状态下时
		case NORMAL:
		    //(1)当源文件中取出'/'时,则将'/'写入目标文件并且状态变为遇到'/'状态。
			if (ch == '/') 
			{
				fputc('/', output);
				state = FOUND_SLASH;
			}
			//(2)当源文件取出其他字符时,则直接将该字符写入到目标文件并且状态仍为普通状态。
			else
			{
				fputc(ch, output);
				state = NORMAL;
			}
			break;
		//2.当在遇到'/'状态下时
		case FOUND_SLASH:
			//(1)当源文件取出'*'时,则表示为C注释,需要转换为C++注释,故将'/'写入目标文件并且状态变为C注释状态。
			if (ch == '*')
			{
				fputc('/', output);
				state =C_COMMENT;
			}
			//(2)当源文件取出'/'时,则直接将'/'写入到目标文件并且状态变为C++注释状态。
			else if (ch == '/')
			{
				fputc('/', output);
				state = CPP_COMMENT;
			}
			//(3)当源文件取出其他字符时,表示不是注释语句,故直接写入到目标文件并且状态变为普通状态。
			else
			{
				fputc(ch, output);
				state = NORMAL;
			}
			break;
		//3. 当在C++注释状态时
		case CPP_COMMENT:
			//(1)当源文件取出'\n'时,则直接将'\n'写入目标文件并且状态变为普通状态。
			if (ch == '\n')
			{
				fputc('\n', output);
				state = NORMAL;
			}
			//(2)当源文件取出其他字符时,则直接将其写入目标文件并且状态仍为C++注释状态。
			else
			{
				fputc(ch, output);
				state = CPP_COMMENT;
			}
			break;
		//4.当在C注释状态时
		case C_COMMENT:
			//(1)当源文件取出'*'时
			if (ch == '*')
			{
				next = fgetc(input);
				//①再次读取源文件当取出为'*'时,则将第二次读取到的'*'写入目标文件并且状态变为遇到'*'状态。
				if (next == '*')
				{
					fputc('*', output);
					state = FOUND_STAR;
				}
				// ②再次读取源文件当取出为'/'时,将此次取出的字符返还源文件并且状态变为遇到'*'状态。
				else if (next == '/')
				{
					ungetc(next, input);
					state = FOUND_STAR;
				}
				//③再次读取源文件当取出为其他字符时,则直接将其写入目标文件并且状态变为遇到'*'状态。
				else
				{
					fputc(ch, output);
					state = C_COMMENT;
				}
			}
			//(2)当源文件取出'\n'时,此时需要换行并且仍然在C注释中,故下一行仍然为注释语句
			//故需要将'\n'和'/'和'/'写入目标文件并且状态仍然为C注释状态。
			else if (ch == '\n')
			{
				fputc('\n', output);
				fputc('/', output);
				fputc('/', output);
			}
			//(3)当源文件取出其他字符时,则直接将其写入到目标文件并且状态仍为C注释状态。
			else
			{
				fputc(ch, output);
				state = C_COMMENT;
			}
			break;
		//5.当在遇到'*'状态时
		case FOUND_STAR:
			//(1)当源文件取出'*'时,则直接将'*'写入到目标文件并且状态仍然为遇到'*'状态。
			if (ch == '*')
			{
				fputc('*', output);
				state = FOUND_STAR;
			}
			//(2)当源文件取出'/'时,则表示C注释结束,判断下一次取出的字符是否为'\n'
			else if (ch == '/')
			{
				next = fgetc(input);
				//①则再次读取源文件当取出为'\n'时则直接将第二次读取到的'\n'写入到目标文件并且状态变为普通状态。
				if (next == '\n')
				{
					fputc(next, output);
					state = NORMAL;
				}
				//②则再次读取源文件当取出不是'\n'时则需要自己将'\n'写入到目标文件
				//并且将第二次读取到的字符返还给源文件(使用ungetc()函数),状态变为普通状态。
				else
				{
					fputc('\n', output);
					ungetc(next, input);
					state = NORMAL;
				}
			}
			//(3)当源文件取出其他字符时,则直接将其写入到目标文件并且状态变为C注释状态。
			else
			{
				fputc(ch, output);
				state = C_COMMENT;
			}
			break;
		}
	}
}
以上就是关于注释转换的项目!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章