注释转换(c—>c++)

每天进步一点点!


本题目要求我们编写一个可以将c风格(/**/)的注释转换为c++风格(//)的注释。


在代码注释时,我们可以使用/* ... */注释,中间为被注释的内容,这种注释方式允许我们一次性注释多行,还有一种:// ... ,这种注释一次最多只能注释一行,前者被称为为c风格的注释,后者被称为c++风格的注释。


我们通过状态机思路来完成注释转换,先解释一下状态机:通俗的将就是一组状态之间,依据一定条件,进行状态的转换,它有至少一个出口状态,即达到出口状态时,转换结束。


现将完整代码贴出,后面分析部分代码:


头文件

commentConvert.c

#ifndef __COMMET_CONVERT__
#define __COMMET_CONVERT__

#include <stdio.h>
#include <windows.h>
#include <assert.h>

#pragma warning(disable:4996)

#define INPUT_FILE "input.c"
#define OUTPUT_FILE "output.c"


//状态常量
typedef enum STATUS
{
	NORMAL_STATUS,
	C_STATUS,
	CPP_STATUS,
	END_STATUS,
}status_t;

extern status_t gStatus;
void convertBagin();

#endif


函数实现

commentConvert.c

#include "commentConvert.h"

status_t gStatus = NORMAL_STATUS;

//处理正常状态
static void doNormalStatus(FILE* in, FILE* out)
{
	int first = fgetc(in);
	int second = 0;

	assert(in);
	assert(out);

	switch(first){
	case '/' :
		second = fgetc(in);
		if( '*'== second){
			fputc('/', out);
			fputc('/', out);
			gStatus = C_STATUS;
		}else
			if('/' == first){
				fputc(first, out);
				fputc(first, out);
				gStatus = CPP_STATUS;
			}
			else{
				fputc(first, out);
				fputc(first, out);
			}
		break;
	case EOF:
		gStatus = END_STATUS;
		break;
	default:
		fputc(first, out);
		break;
	}

}

//处理c状态
static void doCStatus(FILE* in, FILE* out)
{
	int first = fgetc(in);
	int second = 0;
	int third = 0;

	assert(in);
	assert(out);

	switch(first){
	case '*' :
		second = fgetc(in);
		if('/' == second){
			third = fgetc(in);
			if('\n' == third){
				fputc('\n', out);
			}else{
				fputc('\n', out);
				ungetc(third, in);
			}
			gStatus = NORMAL_STATUS;
		}
		else{
			fputc(first, out);
			ungetc(second, in);
		}

		break;
	case EOF :
		gStatus = END_STATUS;
		break;
	case '\n':
		fputc(first, out);
		fputc('/', out);
		fputc('/', out);
		break;
	default:
		fputc(first, out);
		break;
	}
}

//处理cpp状态
static void doCppStatus(FILE* in, FILE* out)
{
	int first = fgetc(in);

	assert(in);
	assert(out);
	switch(first){
	case '\n' :
		fputc(first, out);
		gStatus = NORMAL_STATUS;
		break;
	case EOF :
		gStatus = END_STATUS;
		break;
	default:
		fputc(first, out);
		break;
	}
}

//状态机
static void statusMachine(FILE* in, FILE* out)
{
	assert(in);
	assert(out);

	while(END_STATUS != gStatus){//根据状态进入相应逻辑
		switch(gStatus){
		case NORMAL_STATUS:
			doNormalStatus(in, out);
			break;
		case C_STATUS :
			doCStatus(in, out);
			break;
		case CPP_STATUS :
			doCppStatus(in, out);
			break;
		case END_STATUS :
			break;
		default:
			break;
		}
	}
}

//注释转换开始
void convertBagin()
{
	FILE* in = fopen(INPUT_FILE, "r");
	FILE* out = fopen(OUTPUT_FILE, "w");//打开要转换的文件

	if(NULL == in){
		perror("fopen");
		exit(1);
	}
	
	if(NULL == out){
		perror("fopen");
		exit(2);
	}

	statusMachine(in, out);//进入状态机开始转换

	fclose(in);
	fclose(out);//关闭文件
}




主函数

commentConvertMain.c

#include "commentConvert.h"

int main()
{

	printf("Start convert...\n");
	convertBagin();
	printf("Done...\n");

	system("pause");
	return 0;
}


下面用状态机的思路来分析代码。


如图所示,只有触发图中几个条件时,状态机的状态才会发生改变,状态机出口条件为EOF,即读到文件结尾,所以,我们每次读取从输入文件中读取一个字符时,通过判断来改变状态,再进行相应操作,下面结合代码分析部分细节。


doCStatus分析:

由于是将c注释风格转换为c++风格,所以当读取到 /* 时需将其转换为 //,且当读取到 /* 时状态应变为cStatus。

在c状态下,由于其允许多行注释,所以该状态就有以下几种情况:

1、读到 '*' 并且读到 '/' ,后面为 '\n',此种情况下则直接转为正常状态,情况如下:

/*Hello world!*/
2、读到 '*' 并且读到 '/',但后面还有内容,则应该换行,情况如下:

/*Hello world*/int i = 10;
如果不进行换行,由于前面的 /* 已经转换为 // ,后面代码也会被注释掉;

3、读到文件结尾(EOF),则直接转为为EOF状态;
4、除上述之外的情况,均不作状态转换,直接将读到的字符写到output文件中。


其它情况均按照此思路处理。


转换前后的代码如下所示:


转换前:

/*hello world*/
 
/*hello bit
world
aaa
*/
 
/*hello bit*/ int a = 10;

//int main()
{
	printf("hello world\n");
	system("pause");
	return 0;
	
//hello bit
/**/
}


转换后:

//hello world
 
//hello bit
//world
//aaa
// 
 
//hello bit
int a = 10;

//int main()
{
	printf("hello world\n");
	system("pause");
	return 0;
	
//hello bit
//
}


成于坚持,败于止步!

【作者:果冻 http://blog.csdn.net/jelly_9

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值