这篇博客,我将整理关于注释转换的知识,首先,得知道,注释转换包括,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状态是不会到结束状态的。
下边来看源码(便于读者理解,所以代码中写的注释可能比较通俗易懂一点,也不是特
别专业):
//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函数调用之后。
这是我在写这个小项目过程中遇到的问题,希望读者会注意~~当然,还有谁会像我这么
笨,犯这样的错误~~