c语言小项目----注释转换

这篇博客,我将整理关于注释转换的知识,首先,得知道,注释转换包括,c语言注释转

换成c++注释,和c++注释转换成c语言注释。

c语言注释的风格:/*这是c语言注释*/

c++语言注释风格://这是c++注释风格

下面,我主要分析将所有的注释转换成c++注释,即就是c语言注释转换成c++注释。

这样的转换会存在以下多种情况:

1.一般情况:/* int i = 0;*/转换后就是//int i = 0;

2.换行问题:
       /* int i = 0; */int j = 0;
      /* int i = 0; */
      int j = 0;

3.匹配问题:
/*int i = 0;/*xxxxx*/转换后就是//int i = 0;/*xxxxx

4.多行注释问题:
/*
int i=0;
int j = 0;
int k = 0;
*/int k = 0;    

转换后就是:

                    //
                    //int i = 0;
                    //int j = 0;
                   //int k = 0;
                  //
                  int k = 0;
5.连续注释问题:

/**//**/

转换后就是://

                    //

6.连续的**/问题:
/***/

转换后就是://*

7.C++注释问题:
// /*xxxxxxxxxxxx*/

转换后还是// /*xxxxxxxxxxxx*/

8.字符串里的注释:

"/*helloyaoyao*/"

转换后还是:"/*helloyaoyao*/"

由于情况比较大,所以,我们运用一个叫做有限状态机的东西~~

我们主要的工作是将input.c里的内容通过注释转换写进output.c里。

有限状态机:

有限状态机FSM是软件上常用的一种处理⽅法,它把复杂的控制逻辑分解成有限个稳定

状态,在每个状态上进行处理。有限状态机是闭环系统,可以用有限的状态,处理无穷

的事务。

关于c注释到c++注释的状态转换图如下:

c语言小项目----注释转换_第1张图片

c状态是不会到结束状态的。

下边来看源码(便于读者理解,所以代码中写的注释可能比较通俗易懂一点,也不是特

别专业):

//test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"commentconvert.h"
int main()
{
	FILE *pfRead = NULL;
	FILE *pfWrite = NULL;
	printf("注释开始\n");
	pfRead = fopen(INPUTNAME, "r");
	if (NULL == pfRead)
	{
		perror("open file for read");
		exit(EXIT_FAILURE);
	}
	pfWrite = fopen(OUTPUTNAME, "w");
	if (NULL == pfWrite)
	{
		fclose(pfRead);
		perror("open file for write");
		exit(EXIT_FAILURE);
	}
	commentcovert(pfRead, pfWrite);
	printf("注释结束\n");
	system("pause");
	return 0;
}
//commentconvert.h
#ifndef  __COMMENTCOVERT_H__
#define  __COMMENTCOVERT_H__
#define INPUTNAME "input.c"
#define OUTPUTNAME "output.c"
#include<stdio.h>
#include<stdlib.h>
enum STATE
{
	NUL_STATE,
	C_STATE,
	CPP_STATE,
	END_STATE,
	STR_STATE
};

void commentcovert(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);
void Do_STR_STATE(FILE *pfRead, FILE *pfWrite);
#endif//
//commentconvert.c
#include"commentconvert.h"
enum STATE state = NUL_STATE;
void commentcovert(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 STR_STATE:
			Do_STR_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);
	switch (first)
	{
	case '/':
		second = fgetc(pfRead);
		if (second == '/')
		{
			fputc('/', pfWrite);
			fputc('/', pfWrite);
			state = CPP_STATE;   //在无状态下遇到//直接将//写进去,并进入cpp状态
		}
			else if (second == '*')
			{
				fputc(first, pfWrite);
				fputc('/', pfWrite);
				state = C_STATE;//在无状态下遇到/*要将/*变成//写进去,并进入c状态
			}
			else
			{
				fputc(first, pfWrite);
				fputc(second, pfWrite);//如果遇到其他字符,直接写进去,状态不改变。
			}
			break;
		case EOF:
			state = END_STATE;//如果遇到EOF,进入结束状态
			break;
		case '"':
			fputc(first, pfWrite);
			state = STR_STATE;//如果遇到",进入字符串状态
			break;
		default:
			fputc(first, pfWrite);//其他情况的字符,直接写进去就行
			break;
		}
}
void Do_STR_STATE(FILE *pfRead,FILE *pfWrite)
{
	int first = 0;
	first = fgetc(pfRead);
	switch (first)
	{
	case '"':
		fputc(first, pfWrite);
		state = NUL_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);
		if (second == '/')  // 遇到*/ 说明c的注释结束,切换到无状态
		{
			state = NUL_STATE;
			third = fgetc(pfRead);
			if (third != '\n')
			{
				fputc('\n', pfWrite);    //如果/后边的字符不是回车,需要写进去回车,然后再把独到的字符放回
				ungetc(third, pfRead);
			}
			else
			{
				ungetc(third, pfRead);//如果是回车,把回车放回
			}
		}                           
		else
		{
			fputc(first, pfWrite);          
			//如果遇到*,但是后边不是/,把*放进去,*后边的字符放回,比如,/***/,进入c状态以后,
			//遇到*,后边的字符也是*,如果把两个*都写进去,后边就只剩下/,就不能找到c状态结束的标志,
			//所以,需要把第二个字符原样写回
			/*fputc(second, pfWrite);*/
			ungetc(second,pfRead);    //放回
		}
		break;
	case '\n':
		fputc(first, pfWrite);//如果需要回车,吧回车写入,在写入//,状态不变。
		fputc('/', pfWrite);
		fputc('/', pfWrite);
		break;
	default:
		fputc(first, pfWrite);
		break;
	}
}
void Do_CPP_STATE(FILE *pfRead, FILE *pfWrite)
{
	int first = 0;
	int second = 0;
	first = fgetc(pfRead);
	switch (first)
	{
	case '\n':
		fputc(first,pfWrite);//cpp状态,如果遇到回车,cpp状态结束,进入无状态
		state = NUL_STATE;
		break;
	default:
		if (first == EOF)
		{
			state = END_STATE;
		}
		else
		{
			fputc(first, pfWrite);
		}
			break;
		}
}

加入代码之后,竟然发现好丑~~~希望理解。

代码的测试用例:



下边我来谈一下关于写代码时的一些失误:

1.写代码之前,没有将思路整理好,导致出错了也不知道从哪开始调试,排查。

2.对有限状态转移的不理解:比如c状态下没有遇到*/,遇到了其他一般字符,仍然需要

停留在c状态;还有,状态被改变之后,不用人为地调用commentconvert函数,因为进

入当前状态是从commentconvert函数进入的,所以结束当前状态后也会回到commentconvert函数,while循环帮我们实现了。也是因为多余。。

3.state是一个全局变量,软件工程课学到,尽量不要使用全局变量,是因为它不安全,

想改就能改,根据他的这个特性,我们可以做到状态转换。但是,定义全局变量,你也

不要得寸进尺----将全局变量定义在头文件中,这样全局变量在每个文件中都可以被使

用,被改变,而我们只要在我们当前的文件中使用。如果一个工程不是一个人完成,那

么其他人的不留意也会改变它,所以,这样就不好了。(反正意思就是这个了)

4.打开文件就关闭文件,如果读取打开失败,关闭文件再报告错误;如果程序顺利执行

之后,也要关闭文件,粗心的我并没有关闭,以下这两句代码:

fclose(pfRead);
fclose(pfWrite);
应该添加在测试文件的 commentconvert函数调用之后。


这是我在写这个小项目过程中遇到的问题,希望读者会注意~~当然,还有谁会像我这么

笨,犯这样的错误~~大笑



你可能感兴趣的:(注释转换)