让我们来实现一个注释转换器。它可以将拥有c风格(/* code */)或c++风格(// code)的注释的代码转换为c++风格。
刚开始看到这个题目是有点头晕的,因为各种注释的混合将使情况变得非常复杂,比如:
// 1.一般情况
/* int i = 0; */
// 2.换行问题
/* int i = 0; */int j = 0;
/* 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++注释问题
// /*xxxxxxxxxxxxxxxxxxxx*/这里只列举了几种情况,当然还有更多。所以想要单纯的通过if-else语句判断是很麻烦很麻烦的。由此,我们就想通过某种方法将这么多的复杂情况简化为几种状态,在这几种为数不多的状态里区分逻辑那就一目了然了。所以有限状态机来了。
有限状态机,(英语:Finite-state machine, FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
由这个思路,我们可以画出如下模型(当然只是随便画画,并不严谨):
按注释风格将代码分为几种状态:
非注释代码称为无状态,c风格注释称为C转态,C++风格注释称为CPP状态,文件结束称为END状态。
箭头旁边的标注代表状态转换的条件,例如无状态指向C转态的箭头,意义为当在无状态下,遇到 '/*'则切换为C状态。
理清了这些逻辑,我们便可以很好的在各个转态之间切换了。下面贴上我写的代码(input.c作为测试代码源,output.c作为输出文件,都放在当前目录下):
头文件annotation_converter.h:
#ifndef __ANNOTATION_CONCERTER__ #define __ANNOTATION_CONCERTER__ #include <stdio.h> #include <stdlib.h> #define INPUT_FILE_NAME "input.c" #define OUTPUT_FILE_NAME "output.c" typedef enum state { NULL_STATE, C_STATE, CPP_STATE, END_STATE }STATE_TYPE; void converter(void); //核心转换函数 void converter_core(FILE *read, FILE *write); //无状态处理 void converter_NULL(FILE *read, FILE *write, STATE_TYPE *pstate); //C状态处理 void converter_c(FILE *read, FILE *write, STATE_TYPE *pstate); //CPP状态处理 void converter_cpp(FILE *read, FILE *write, STATE_TYPE *pstate); #endif
具体实现文件annotation_converter.c:
#define _CRT_SECURE_NO_WARNINGS #include "annotation_converter.h" #include <assert.h> void converter_NULL(FILE *read, FILE *write, STATE_TYPE *pstate) { int first = 0, second = 0; while (*pstate == NULL_STATE) { first = fgetc(read); switch (first) { case '/': { second = fgetc(read); switch (second) { case '/': fputc(first, write); fputc(second, write); *pstate = CPP_STATE; break; case '*': fputc(first, write); fputc('/', write); *pstate = C_STATE; break; default: fputc(first, write); fputc(second, write); break; } } break; case EOF: *pstate = END_STATE; break; default: fputc(first, write); break; } } } void converter_c(FILE *read, FILE *write, STATE_TYPE *pstate) { int first = 0, second = 0, third = 0; int flag = 0; while (C_STATE == *pstate) { if (flag == 0) first = fgetc(read); switch (first) { case '*': { second = fgetc(read); if ('/' == second) { third = fgetc(read); if (third != '\n') fputc('\n', write); ungetc(third, read); //flag = 0; *pstate = NULL_STATE; } else if ('*' == second) { fputc(first, write); first = second; flag = 1; } else { fputc(first, write); fputc(second, write); } } break; case '\n': fputc(first, write); fputc('/', write); fputc('/', write); break; case EOF: *pstate = END_STATE; break; default: fputc(first, write); break; } } } void converter_cpp(FILE *read, FILE *write, STATE_TYPE *pstate) { int first = 0, second = 0; while (CPP_STATE == *pstate) { first = fgetc(read); switch (first) { case '\n': fputc(first, write); *pstate = NULL_STATE; break; case EOF: *pstate = END_STATE; break; default: fputc(first, write); break; } } } void converter_core(FILE *read, FILE *write) { STATE_TYPE code_state = NULL_STATE; assert(read); assert(write); while (1) { switch (code_state) { case NULL_STATE: converter_NULL(read, write, &code_state); break; case C_STATE: converter_c(read, write, &code_state); break; case CPP_STATE: converter_cpp(read, write, &code_state); break; case END_STATE: return; break; default: break; } } } void converter() { FILE *read = NULL; FILE *write = NULL; read = fopen(INPUT_FILE_NAME, "r"); if (NULL == read) { perror("打开源文件错误\n"); exit(0); } write = fopen(OUTPUT_FILE_NAME, "w"); if (NULL == write) { perror("打开目标文件错误\n"); fclose(read); exit(0); } converter_core(read, write); fclose(read); fclose(write); }
测试文件 test.c:#include "annotation_converter.h" int main() { printf("annotaation_converter test\n"); converter(); return 0; }
input.c:
// 1.一般情况 /* int i = 0; */ // 2.换行问题 /* int i = 0; */int j = 0; /* 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++注释问题 // /*xxxxxxxxxxxxxxxxxxxx*/
output.c初始为空文件,执行程序后:
当然你也可以改用其它的input.c来测试。这里就不在试了。// 1.一般情况 // int i = 0; // 2.换行问题 // int i = 0; int j = 0; // 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++注释问题 // /*xxxxxxxxxxxxxxxxxxxx*/
注释转换器
最新推荐文章于 2019-06-28 18:29:04 发布