由于最近在读一些开源代码,大段的注释读起来不太方便,于是产生了想用C语言实现自动删除代码中所有注释的想法。
C语言中注释分为以下几种
1) /* hello world */
2) // hello world
3) #if 0
hello world
#endif
表面上看起来很简单,其实实现起来比较复杂,有很多细节需要处理,比如注释和引号互相嵌套的问题,/* "hello */ " world */, "/* hello */"。还有比如删除注释后需要适当调整格式使其整齐美观。
目前C语言中的主流注释方式为第一种,故暂时只实现了第一种,其实原理都是一样的。核心原理即为状态机,读入一个字符,根据当前状态和读入的字符转入下一个状态,每一个状态都有相应的动作处理读入的字符,如忽略或写入输出文件或退出上一个字符等等。
共有以下几个状态
#define STATUS_OUTTE 0 /* 在注释和引号外面 */
#define STATUS_DOTTE 1 /* 在引号内部 */
#define STATUS_STIN1 2 /* 读入 /,等待 * */
#define STATUS_STIN2 3 /* 读入 /* , 准备进入注释 */
#define STATUS_STINN 4 /* 在注释内部 */
#define STATUS_STOU1 5 /* 读入 * , 等待 / */
#define STATUS_STOU2 6 /* 读入 */, 准备离开注释 */
#define STATUS_STACT 7 /* 伪状态,表示状态机动作 */
状态机有以下几种动作
#define STFLAG_NOACT 0 /* 没动作,忽略字符 */
#define STFLAG_FPUTC 1 /* 将字符写入输出文件 */
#define STFLAG_UNPUT 2 /* 将上一个字符退出 */
完整实现如下
- /*
- comment.h
- */
- #ifndef _comment_h
- #define _comment_h
- void comment(char *inpath, char *outpath);
- #endif
- /*
- comment.c
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include "comment.h"
- #define STATUS_OUTTE 0
- #define STATUS_DOTTE 1
- #define STATUS_STIN1 2
- #define STATUS_STIN2 3
- #define STATUS_STINN 4
- #define STATUS_STOU1 5
- #define STATUS_STOU2 6
- #define STATUS_STACT 7
- #define STFLAG_NOACT 0
- #define STFLAG_FPUTC 1
- #define STFLAG_UNPUT 2
- static FILE *fpin, *fpout;
- static int status_table[8][128];
- static int status = STATUS_OUTTE;
- #define st(i, j) status_table[(i)][(j)]
-
- static void set_status_table(int i, int j, int s)
- {
- if (j != -1) st(i, j) = s;
- else {
- for (j = 0; j < 128; j++)
- status_table[i][j] = s;
- }
- }
- static void init_status(void)
- {
- set_status_table(STATUS_OUTTE, -1 , STATUS_OUTTE);
- set_status_table(STATUS_OUTTE, '/', STATUS_STIN1);
- set_status_table(STATUS_OUTTE, '"', STATUS_DOTTE);
- set_status_table(STATUS_DOTTE, -1 , STATUS_DOTTE);
- set_status_table(STATUS_DOTTE, '"', STATUS_OUTTE);
-
- set_status_table(STATUS_STIN1, -1 , STATUS_OUTTE);
- set_status_table(STATUS_STIN1, '/', STATUS_STIN1);
- set_status_table(STATUS_STIN1, '*', STATUS_STIN2);
- set_status_table(STATUS_STIN1, '"', STATUS_DOTTE);
-
- set_status_table(STATUS_STIN2, -1 , STATUS_STINN);
- set_status_table(STATUS_STIN2, '*', STATUS_STOU1);
-
- set_status_table(STATUS_STINN, -1 , STATUS_STINN);
- set_status_table(STATUS_STINN, '*', STATUS_STOU1);
-
- set_status_table(STATUS_STOU1, -1 , STATUS_STINN);
- set_status_table(STATUS_STOU1, '*', STATUS_STOU1);
- set_status_table(STATUS_STOU1, '/', STATUS_STOU2);
-
- set_status_table(STATUS_STOU2, -1 , STATUS_OUTTE);
- set_status_table(STATUS_STOU2, '"', STATUS_DOTTE);
- set_status_table(STATUS_STOU2, '/', STATUS_STIN1);
-
- set_status_table(STATUS_STACT, STATUS_OUTTE, STFLAG_FPUTC);
- set_status_table(STATUS_STACT, STATUS_DOTTE, STFLAG_FPUTC);
- set_status_table(STATUS_STACT, STATUS_STIN1, STFLAG_FPUTC);
- set_status_table(STATUS_STACT, STATUS_STIN2, STFLAG_UNPUT);
- set_status_table(STATUS_STACT, STATUS_STINN, STFLAG_NOACT);
- set_status_table(STATUS_STACT, STATUS_STOU1, STFLAG_NOACT);
- set_status_table(STATUS_STACT, STATUS_STOU2, STFLAG_NOACT);
- }
- #define file_noact ((status_handler_t)0)
- typedef void (*status_handler_t)(char);
- static void file_putc(char c);
- static void file_unputc(char c);
- static void status_handler(char c)
- {
- const status_handler_t handler_a[] = {
- file_noact, file_putc, file_unputc
- };
- int actidx = st(STATUS_STACT, status);
- status_handler_t handler = handler_a[actidx];
- if (handler != NULL) handler(c);
- }
- static void show_status(char c);
- void comment(char *inpath, char *outpath)
- {
- char c;
- init_status();
- fpin = fopen(inpath, "r");
- fpout = fopen(outpath, "w");
- assert(fpin && fpout != NULL);
- while ((c = fgetc(fpin)) != EOF) {
- show_status(c);
- if (c == '\r') continue;
- status = st(status, (int)c);
- status_handler(c);
- }
- }
- ///////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////
- static char *c_str(char c, char *buf, int size)
- {
- if (c == ' ') return "_";
- else if (c == '\t') return "\\t";
- else if (c == '\n') return "\\n";
- else if (c == '\r') return "\\r";
- else if (c == '\0') return "\\0";
- snprintf(buf, size, "%c", c);
- return buf;
- }
- #define RET_STATUS_STRING(s) \
- if (status == (s)) return #s
-
- static char *status_str(void)
- {
- RET_STATUS_STRING(STATUS_OUTTE);
- RET_STATUS_STRING(STATUS_DOTTE);
- RET_STATUS_STRING(STATUS_STIN1);
- RET_STATUS_STRING(STATUS_STIN2);
- RET_STATUS_STRING(STATUS_STINN);
- RET_STATUS_STRING(STATUS_STOU1);
- RET_STATUS_STRING(STATUS_STOU2);
- return "invalid status";
- }
- static void show_status(char c)
- {
- char t[4];
- fprintf(stdout, ">>> %s, %s\n",
- status_str(), c_str(c, t, sizeof t));
- }
- #define MAXLINE 128
- static char linebuf[MAXLINE];
- static char *lineptr = linebuf;
- static void init_line_buf(void)
- {
- memset(linebuf, 0, sizeof linebuf);
- lineptr = linebuf;
- }
- #define isblank(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
- /* is writable */
- static int is_wrt(void)
- {
- char c, *ptr = linebuf;
- for ( ; (c = *ptr); ptr++) {
- if (isblank(c) == 0)
- return 1;
- }
- return 0;
- }
- static void file_puts(void)
- {
- static int lines; /* empty lines */
- if (is_wrt())
- lines = 0;
- else lines++;
- if (lines > 1)
- return;
- int len = strlen(linebuf);
- fwrite(linebuf, len, 1, fpout);
- }
- static void file_putc(char c)
- {
- *lineptr++ = c;
- if (c == '\n') {
- file_puts();
- init_line_buf();
- }
- }
- static void file_unputc(char c)
- {
- *--lineptr = 0;
- }
- /*
- main.c
- */
- #include <assert.h>
- #include "comment.h"
- int main(int argc, char *argv[])
- {
- assert(argc == 3);
- comment(argv[1], argv[2]);
- return 0;
- }
阅读(7838) | 评论(0) | 转发(3) |