C语言注释转换是C语言内比较小的一个课题,这个课题的主要思想是需要考虑到可能出现的情况,然后转换为我们能用程序语言描述的情形。
一般可以分为7种情形:
1.一般情况
/* int i = 0; */
2.换行问题
/* 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 */
在这里每一种情形都可以分步讨论,先判断第一个读取的字符,如果是‘/’ ,就可以考虑是否会出现上面说的情形;如果不是,直接读取然后写入另一个文件中。如果是‘/’,接下来继续判断下一个可能会出现的情况,出现‘*’就跳到C语言转换的函数;如果是‘/’,那么就跳到C++语言转换的函数;如果是其他字符,直接读取然后存入文件中。
//头文件声明部分
#ifndef __COMMENTCONVERT_H__
#define __COMMENTCONVERT_H__
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
enum STATE //定义4个状态
{
NUL_STATE, //无状态,也就是正常状态
C_STATE, //C语言状态
CPP_STATE, //C++状态
END_STATE //文件读取完成
};
void DoConvert(FILE *pfIn,FILE *pfOut);
void DoNULLState(FILE *pfIn,FILE *pfOut,enum STATE *psta);
void DoCState(FILE *pfIn,FILE *pfOut,enum STATE *psta);
void DoCppState(FILE *pfIn,FILE *pfOut,enum STATE *psta);
#endif
//主要函数部分
#include"CommentConvert.h"
void DoConvert(FILE *pfIn,FILE *pfOut) //判断可能出现的情形
{
enum STATE state=NUL_STATE; //开始的时候设置为无状态
while(state!=END_STATE) //用while循环控制整个程序的执行
{
switch(state)
{
case NUL_STATE:
{
DoNULLState(pfIn,pfOut,&state);
break;
}
case C_STATE:
{
DoCState(pfIn,pfOut,&state);
break;
}
case CPP_STATE:
{
DoCppState(pfIn,pfOut,&state);
break;
}
case END_STATE:
break;
default:
break;
}
}
}
void DoNULLState(FILE *pfIn,FILE *pfOut,enum STATE *psta) //无状态
{
char first=0;
char second=0;
first=fgetc(pfIn);
switch(first) //判断第一个读取的字符是什么
{
case '/':
{
second=fgetc(pfIn);
switch(second)
{
case '*': //1.一般情况
{
fputc('/',pfOut);
fputc('/',pfOut);
*psta=C_STATE;
break;
}
case '/': //7.C++注释问题
{
fputc(first,pfOut);
fputc(second,pfOut);
*psta=CPP_STATE;
break;
}
default:
{
fputc(first,pfOut);
fputc(second,pfOut);
break;
}
}
break;
}
case EOF: //文件结束标志
{
fputc(first,pfOut);
*psta=END_STATE;
break;
}
default:
{
fputc(first,pfOut);
break;
}
}
}
void DoCState(FILE *pfIn,FILE *pfOut,enum STATE *psta) //C语言状态
{
char first=0;
char second=0;
char third=0;
first=fgetc(pfIn);
switch(first) //3.匹配问题
{
case '*':
{
second=fgetc(pfIn);
switch(second)
{
case '/':
{
third=fgetc(pfIn);
*psta=NUL_STATE;
if(third=='\n') //2.换行问题
fputc('\n',pfOut);
else
{
fputc('\n',pfOut);
ungetc(third,pfIn);
}
break;
}
case '*': // 6.连续的**/问题
{
fputc(first,pfOut);
ungetc(second,pfIn);
break;
}
default:
{
fputc(first,pfOut);
fputc(second,pfOut);
break;
}
}
break;
}
case '\n': //4.多行注释问题
{
fputc('\n',pfOut);
fputc('/',pfOut);
fputc('/',pfOut);
*psta=C_STATE;
break;
}
default:
{
fputc(first,pfOut);
break;
}
}
}
void DoCppState(FILE *pfIn,FILE *pfOut,enum STATE *psta) //C++状态
{
char first=0;
char second=0;
first=fgetc(pfIn);
switch(first)
{
case '\n':
{
fputc(first,pfOut);
*psta=NUL_STATE;
break;
}
case EOF:
{
*state = END_STATE;
break;
}
default:
{
fputc(first,pfOut);
break;
}
}
}
//测试函数
#include<stdio.h>
#include<stdlib.h>
#include"CommentConvert.h"
int main()
{
FILE *pfIn;
FILE *pfOut;
pfIn=fopen("input.c","r");
if(pfIn==NULL)
{
perror("open file failed");
exit(EXIT_FAILURE);
}
pfOut=fopen("output.c","w");
if(pfOut==NULL)
{
fclose(pfIn);
perror("open failed\n");
exit(EXIT_FAILURE);
}
DoConvert(pfIn, pfOut);
fclose(pfIn);
pfIn=NULL;
fclose(pfOut);
pfOut=NULL;
system("pause");
return 0;
}
结果如下:
总结:
1.本人在写过程中,第一个出现的问题是提示是“open file failed”。反复检查看好几遍,很确定自己建立了这两个文件。最后的最后才发现文件名多了一个字母,满屏的尴尬脸啊!
2.文件正常执行后,发现在换行和多行注释的过程中int的i老丢,调试好几次后发现是在写C语言状态的时候没有考虑清楚应该给缓存区放第几个字符。一定要记住在”ungetc(third,pfIn)“中,我们已经判断到第三个字符了,所以放的也是第三个!读取哪个字符就要对哪个字符负责,千万不能“始乱终弃”!
3.有问题一定要去调试!调试!在调试前可以通过对错误现象的分析,初步估计一下问题可能出现在哪里,然后一步一步调试,直到完全找到错误出现的地方。