小项目:简单注释转换(C风格转到C++风格)


C的注释是以字符 /* 开始,以字符 */ 结束,注释被包含的内容。C++的注释是以字符 // 开始,碰到换行符 \n 时结束,注释一行。所以,从C注释转到C++,就是在碰到 /* 时将换成 // ,碰到 */ 时 将其删除。当然,这里会有许多种需要细心情况,我们下面再谈。


完成这个项目,我们需要把代码划分4个状态,NULL(无状态),C状态,CPP状态,END状态。没有接触过这个项目的同学对这四个状态可能不太懂,请耐心往下看。

请阅读下面的状态转换图,首先,我们默认代码开始时是NULL 状态。





①当在NULL状态下碰到 /* 时 进入 C状态(同时将 /* 改为 //);

②在C状态下碰到*/,说明C注释已经结束,此时转回到NULL状态(将*/ 删除),进行下一轮新的判断;

③在NULL状态下碰到 // 时,说明c++注释开始,转到CPP状态;

④当在CPP状态下读到 \n 时,说明C++注释结束,此时转回NULL状态,进行下一轮判断;

⑤⑥⑦:当代码读到EOF时,说明代码已经结束,这时转到END状态,结束程序;


上面状态转换图以及序号讲解只说明了状态之间的转换关系,下面我们列举一下将会碰到哪些情况:


// 1.一般情况
/* int i = 0; */


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


我们需要将 int j = 0; 换到下一行,保证有效内容不被注释。
 
// 3.匹配问题
/*int i = 0;/*xxxxx*/


/* 该与那个*/匹配?


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


如何将每行都转换成C++注释?



// 5.连续注释问题
/**//**/


连续的C注释怎么处理?


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


连续的***/又该怎么处理?


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


C++注释中遇到C注释该怎么办?


这个小项目中我只处理了这几种问题,当然还有许多情况需要同学们去发掘。例如:当一个双引号中包含 /**/ 或者 // 又改怎么解决?




既然我们这个项目是对代码进行操作,那么我们的输入输出必须是函数啦。在相同的目录下建立一个 input.c 作为输入。函数执行完毕后,自动生成输出.c文件。






在这里,我声明一下,下面的代码中用到了fputc函数,fgetc函数,流等C语言知识点。不懂得同学自行查阅资料。

接下来我们来看代码。我用的编译软件是VS2010,写这个项目的时候将其分成了三部分。如图:




 Commentconvert.h 是头文件,里面包含了所需的一些宏,枚举类型和操作函数的接口。

#ifndef __COMMENT_CONVERT_H__ //防止头文件重定义错误出现
#define __COMMENT_CONVERT_H__
#include<stdio.h>
#include<stdlib.h>

#define INPUTFILENAME "input.c"//将文件名定义成宏,方便以后的修改
#define OUTPUTFILENAME "output.c"

enum STATE//枚举类型
{
 NUL_STATE,
 C_STATE,
 CPP_STATE,
 END_STATE
};

void Commentconvert(FILE *pread,FILE *pwrite);//总操作函数
void DO_NUL_state(FILE *pread,FILE *pwrite);//NULL状态操作函数
void DO_C_state(FILE *pread,FILE *pwrite);//C状态操作函数
void DO_CPP_state(FILE *pread,FILE *pwrite);//CPP状态操作函数


#endif // __COMMENT_CONVERT_H__


Commentconvert.c中放的是操作函数的代码,与主函数分开是为了便于调试。

#include"Commentconvert.h"
enum STATE state=NUL_STATE;


void DO_NUL_state(FILE *pread,FILE *pwrite)
{
  int first = 0;
  char second = 0;
  first = fgetc(pread);
  switch(first)
  {
  case '/':
<span>	</span>  second = fgetc(pread);
<span>	</span>  if(second=='*')         //NULL状态下 读到 /* 转换到 C状态
<span>	</span>  {
<span>	</span>    fputc('/',pwrite);   // 放入//
<span>		</span>fputc('/',pwrite);
<span>		</span>state = C_STATE;    
<span>	</span>  }
<span>	</span>  else if(second=='/')   //NULL状态下 读到 /* 转换到 C++状态
<span>	</span>  {
<span>	</span>   fputc(first,pwrite);
<span>	</span>   fputc(second,pwrite);
<span>	</span>   state = CPP_STATE;
<span>	</span>  }
<span>	</span>  else
<span>	</span>  {
<span>	</span>   fputc(first,pwrite);
<span>	</span>   fputc(second,pwrite);
<span>	</span>  }
<span>	</span> break;
  case EOF:       //NULL状态下 读到 EOF 转换到 END状态
<span>	</span>  fputc(first,pwrite);
<span>	</span>  state = END_STATE;
<span>	</span>  break;
  default:
<span>	</span>  fputc(first,pwrite);
<span>	</span>  break;
  
  }
}


void DO_C_state(FILE *pread,FILE *pwrite)
{
  char first = 0;
  char second = 0;
  first = fgetc(pread);
  switch(first)
  {
  case '*':
<span>	</span>  second = fgetc(pread);
<span>	</span>  if(second == '/')         //换行问题 当读到 */ 时,我们还得判断它的下一个字符是不是\n ,
                                  
<span>	</span>  { 
<span>		</span>  int third = 0;
<span>		</span>  third = fgetc(pread);
<span>		</span>  if(third == '\n')        //如果是则将\n读到pwrite中,
<span>		</span>  {
<span>			</span> fputc(third,pwrite);
<span>			</span> state = NUL_STATE;
<span>		</span>  }
<span>		</span>  else                         //如果不是,我们则添加一个换行符
<span>		</span>  {
<span>			</span>fputc('\n',pwrite);   
<span>			</span>ungetc(third,pread);
<span>			</span>state = NUL_STATE;
<span>		</span>  }
        
<span>	</span> 
<span>	</span>  }
<span>	</span>  else  //   多个**/问题  如果 * 的下一个字符不是 / ,则将这个字符返还给pread
<span>	</span>  {
<span>	</span>     fputc(first,pwrite);
<span>	</span>     ungetc(second,pread);<span>	</span> 
<span>	</span>  }
<span>	</span>  break;
  case '\n':                  //多行注释问题    C状态下读到\n  放回\n  读到下一行开头 并放入 //
<span>	</span>   fputc(first,pwrite);
<span>	</span>   fputc('/',pwrite);
<span>	</span>   fputc('/',pwrite);
<span>	</span>  break;
  case EOF:               // C状态下读到EOF   换到END 状态
<span>	</span>   fputc(first,pwrite);
<span>	</span>   state = END_STATE;
<span>	</span>   break;
  default:
<span>	</span> fputc(first,pwrite);
<span>	</span> break;
  }
}


void DO_CPP_state(FILE *pread,FILE *pwrite)
{
 char first = 0;
 char second = 0;
 first = fgetc(pread);
 switch(first)
 {
 case '/':
<span>	</span> second = fgetc(pread);  
<span>	</span>  if(second == '*')      //C++状态下遇到 /* 不做操作 并放回
<span>	</span> {
<span>	</span>    fputc(first,pwrite);
<span>	</span>   fputc(second,pwrite);
<span>	</span> }
<span>	</span> else
<span>	</span> {
<span>	</span>   fputc(first,pwrite);
<span>	</span>   fputc(second,pwrite);
<span>	</span> }
<span>	</span> break;


 case EOF:     //c++状态下遇到 EOF  转换到END
<span>	</span> fputc(first,pwrite);
<span>	</span> state = END_STATE;
<span>	</span> break;
 case '\n':           //c++状态下遇到 \n ,转换到NULL状态


<span>	</span> state = NUL_STATE;


 default:
<span>	</span>  fputc(first,pwrite);
<span>	</span>  break;
 }
}
void Commentconvert(FILE *pread,FILE *pwrite)
{
 
  while(state!=END_STATE)
  {
    switch(state)
<span>	</span>{
<span>	</span>case NUL_STATE:
<span>		</span>DO_NUL_state(pread,pwrite);
<span>		</span>break;
<span>	</span>case C_STATE:
<span>		</span>DO_C_state(pread,pwrite);
<span>		</span>break;
<span>	</span>case CPP_STATE:
<span>		</span>DO_CPP_state(pread,pwrite);
<span>		</span>break;
<span>	</span>case END_STATE:
<span>		</span>break;
<span>	</span>}
  }


}

test.c中放的是调试代码,包括主函数。

#include"Commentconvert.h"
 int main()
 {   
	
	 FILE *pread=NULL;
	 FILE *pwrite=NULL;
	 printf("转换开始");
	 pread=fopen(INPUTFILENAME,"r");
	  if(NULL==pread)
	  {
	   printf(" open file for read");
	   exit(EXIT_FAILURE);
	  }
	 pwrite=fopen(OUTPUTFILENAME,"w");

	 if(NULL==pwrite)
	 {
	   fclose(pread);
	   printf(" open file for write");
	   exit(EXIT_FAILURE);
	 }
	 Commentconvert(pread,pwrite);
	 printf("转换结束");
	 fclose(pread); //用完之后,要关闭它。(良好编程习惯)
	 fclose(pwrite);
     return 0;
 }


如果你的代码成功的话,将上面列举的问题输入 input.c,执行代码,你会看到下面的结果。




套用我学长的一句话,为什么选择当程序员,“工资高,自由度大,前景好,有车有房有未来”。 哈哈, 同志们加油!



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值