Chinaunix首页 | 论坛 | 博客
  • 博客访问: 191946
  • 博文数量: 27
  • 博客积分: 725
  • 博客等级: 上士
  • 技术积分: 347
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-04 09:01
文章分类

全部博文(27)

文章存档

2012年(15)

2011年(12)

分类: C/C++

2011-11-20 21:21:07

由于最近在读一些开源代码,大段的注释读起来不太方便,于是产生了想用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 /* 将上一个字符退出   */

完整实现如下

  1. /*
  2.     comment.h
  3. */
  4. #ifndef _comment_h
  5. #define _comment_h

  6. void comment(char *inpath, char *outpath);

  7. #endif
  1. /*
  2.     comment.c
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <assert.h>
  8. #include "comment.h"

  9. #define STATUS_OUTTE 0
  10. #define STATUS_DOTTE 1
  11. #define STATUS_STIN1 2
  12. #define STATUS_STIN2 3
  13. #define STATUS_STINN 4
  14. #define STATUS_STOU1 5
  15. #define STATUS_STOU2 6
  16. #define STATUS_STACT 7

  17. #define STFLAG_NOACT 0
  18. #define STFLAG_FPUTC 1
  19. #define STFLAG_UNPUT 2

  20. static FILE *fpin, *fpout;
  21. static int status_table[8][128];
  22. static int status = STATUS_OUTTE;

  23. #define st(i, j) status_table[(i)][(j)]
  24.         
  25. static void set_status_table(int i, int j, int s)
  26. {
  27.     if (j != -1) st(i, j) = s;
  28.     else {
  29.         for (j = 0; j < 128; j++)
  30.             status_table[i][j] = s;
  31.     }
  32. }

  33. static void init_status(void)
  34. {
  35.     set_status_table(STATUS_OUTTE, -1 , STATUS_OUTTE);
  36.     set_status_table(STATUS_OUTTE, '/', STATUS_STIN1);
  37.     set_status_table(STATUS_OUTTE, '"', STATUS_DOTTE);

  38.     set_status_table(STATUS_DOTTE, -1 , STATUS_DOTTE);
  39.     set_status_table(STATUS_DOTTE, '"', STATUS_OUTTE);
  40.     
  41.     set_status_table(STATUS_STIN1, -1 , STATUS_OUTTE);
  42.     set_status_table(STATUS_STIN1, '/', STATUS_STIN1);
  43.     set_status_table(STATUS_STIN1, '*', STATUS_STIN2);
  44.     set_status_table(STATUS_STIN1, '"', STATUS_DOTTE);
  45.     
  46.     set_status_table(STATUS_STIN2, -1 , STATUS_STINN);
  47.     set_status_table(STATUS_STIN2, '*', STATUS_STOU1);
  48.     
  49.     set_status_table(STATUS_STINN, -1 , STATUS_STINN);
  50.     set_status_table(STATUS_STINN, '*', STATUS_STOU1);
  51.     
  52.     set_status_table(STATUS_STOU1, -1 , STATUS_STINN);
  53.     set_status_table(STATUS_STOU1, '*', STATUS_STOU1);
  54.     set_status_table(STATUS_STOU1, '/', STATUS_STOU2);
  55.     
  56.     set_status_table(STATUS_STOU2, -1 , STATUS_OUTTE);
  57.     set_status_table(STATUS_STOU2, '"', STATUS_DOTTE);
  58.     set_status_table(STATUS_STOU2, '/', STATUS_STIN1);
  59.     
  60.     set_status_table(STATUS_STACT, STATUS_OUTTE, STFLAG_FPUTC);
  61.     set_status_table(STATUS_STACT, STATUS_DOTTE, STFLAG_FPUTC);
  62.     set_status_table(STATUS_STACT, STATUS_STIN1, STFLAG_FPUTC);
  63.     set_status_table(STATUS_STACT, STATUS_STIN2, STFLAG_UNPUT);
  64.     set_status_table(STATUS_STACT, STATUS_STINN, STFLAG_NOACT);
  65.     set_status_table(STATUS_STACT, STATUS_STOU1, STFLAG_NOACT);
  66.     set_status_table(STATUS_STACT, STATUS_STOU2, STFLAG_NOACT);
  67. }            

  68. #define file_noact ((status_handler_t)0)
  69. typedef void (*status_handler_t)(char);

  70. static void file_putc(char c);
  71. static void file_unputc(char c);

  72. static void status_handler(char c)
  73. {
  74.     const status_handler_t handler_a[] = {
  75.         file_noact, file_putc, file_unputc
  76.     };
  77.     int actidx = st(STATUS_STACT, status);
  78.     status_handler_t handler = handler_a[actidx];
  79.     if (handler != NULL) handler(c);
  80. }

  81. static void show_status(char c);

  82. void comment(char *inpath, char *outpath)
  83. {
  84.     char c;
  85.     init_status();
  86.     fpin = fopen(inpath, "r");
  87.     fpout = fopen(outpath, "w");
  88.     assert(fpin && fpout != NULL);
  89.     while ((c = fgetc(fpin)) != EOF) {
  90.         show_status(c);
  91.         if (c == '\r') continue;
  92.         status = st(status, (int)c);
  93.         status_handler(c);
  94.     }        
  95. }
  96. ///////////////////////////////////////////////////////////
  97. //////////////////////////////////////////////////////////
  98. static char *c_str(char c, char *buf, int size)
  99. {
  100.     if (c == ' ') return "_";
  101.     else if (c == '\t') return "\\t";
  102.     else if (c == '\n') return "\\n";
  103.     else if (c == '\r') return "\\r";
  104.     else if (c == '\0') return "\\0";
  105.     snprintf(buf, size, "%c", c);
  106.     return buf;
  107. }

  108. #define RET_STATUS_STRING(s)    \
  109.     if (status == (s)) return #s
  110.     
  111. static char *status_str(void)
  112. {
  113.     RET_STATUS_STRING(STATUS_OUTTE);
  114.     RET_STATUS_STRING(STATUS_DOTTE);
  115.     RET_STATUS_STRING(STATUS_STIN1);
  116.     RET_STATUS_STRING(STATUS_STIN2);
  117.     RET_STATUS_STRING(STATUS_STINN);
  118.     RET_STATUS_STRING(STATUS_STOU1);
  119.     RET_STATUS_STRING(STATUS_STOU2);
  120.     return "invalid status";
  121. }

  122. static void show_status(char c)
  123. {
  124.     char t[4];
  125.     fprintf(stdout, ">>> %s, %s\n",
  126.         status_str(), c_str(c, t, sizeof t));
  127. }

  128. #define MAXLINE 128
  129. static char linebuf[MAXLINE];
  130. static char *lineptr = linebuf;

  131. static void init_line_buf(void)
  132. {
  133.     memset(linebuf, 0, sizeof linebuf);
  134.     lineptr = linebuf;
  135. }

  136. #define isblank(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')

  137. /* is writable */
  138. static int is_wrt(void)
  139. {
  140.     char c, *ptr = linebuf;
  141.     for ( ; (c = *ptr); ptr++) {
  142.         if (isblank(c) == 0)
  143.             return 1;
  144.     }
  145.     return 0;
  146. }

  147. static void file_puts(void)
  148. {
  149.     static int lines; /* empty lines */

  150.     if (is_wrt())
  151.         lines = 0;
  152.     else lines++;
  153.     if (lines > 1)
  154.         return;

  155.     int len = strlen(linebuf);
  156.     fwrite(linebuf, len, 1, fpout);
  157. }

  158. static void file_putc(char c)
  159. {
  160.     *lineptr++ = c;
  161.     if (c == '\n') {
  162.         file_puts();
  163.         init_line_buf();
  164.     }
  165. }

  166. static void file_unputc(char c)
  167. {
  168.     *--lineptr = 0;
  169. }
  1. /*
  2.     main.c
  3. */
  4. #include <assert.h>
  5. #include "comment.h"

  6. int main(int argc, char *argv[])
  7. {
  8.     assert(argc == 3);
  9.     comment(argv[1], argv[2]);
  10.     return 0;
  11. }
阅读(7831) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~