« coLinuxその3 | トップページ | ソースからコメントを削除する2 »

2007年8月 8日 (水)

ソースからコメントを削除する1

車輪の再発明(劣化コピー)の類だと思うが、C言語系のコメントを削除するコードを書いたので、ここにメモしておきます。

  • /* コメント */ 形式のコメントに対応
  • //行末までコメント 形式のコメントに対応
  • 特に2番目の形式では、行末の改行文字はコメントとはみなさずに残す。そのため、一行まるまる//形式のコメントの場合は、末尾の改行のみが残され、結果として空行が出力される。
  • 1番目の形式でも、1行ずつ/* */で閉じられている場合は、同様に空行になるが、複数行が/* 途中で改行 */ で囲まれている場合は、途中に含まれる改行文字は削除される。
  • そのため、空行を削除したい場合は、別のプログラム(grep -v "^$")で削除する必要がある。

コメントの英語がおかしい/コーディングがおかしい/アルゴリズムがおかしい、色々あるかと思いますが、良ければコメントください。

#include <stdio.h>
#include <string.h>
#include "delcmt.h"
/* A main function of this program.
 * 1. check args.
 * 2. open a specified file as an original source code.
 * 3. call delcmt() function, with 2 file streams.
 *    The 1st file stream is original source code,
 *    and the 2nd is stdout which the function write to.
 */
int main(int argc, char *argv[]){
    FILE *fp = NULL;
    if(2 != argc){
        printf("usage:%s src_file\n"
             "This program outputs de-commented code of specified file"
             " to STDOUT.\n", argv[0]);
        return -1;
    }
    if (NULL == (fp = fopen(argv[1], "r"))){
        fprintf(stderr, "can't open %s\n", argv[1]);
    return -1;
  }
  return delcmt(fp, stdout);
}

/* This function reads original source code from a p_in stream
 *  and writes de-commented source code to a p_out stream.
 *  This function does not delete blank line.
 *  *** args ***
 *  FILE *p_in :an original source code stream read from.
 *  FILE *p_out:a de-commented source code stream write to. 
 *
 *  *** return ***
 *  int : 0:OK
 *      -1:NG
 *
 *  *** output ***
 *  This function writes de-commented source code to a file stream p_out.
 *  So, if a p_out is stdout, de-comennted source code is output to STDOUT.
 *    */
int delcmt(FILE *p_in, FILE *p_out){
  int  char0  = 0;
  int  char1  = 0;
  char state  = NON_CMT;
  if(NULL == p_in || NULL == p_out){
    fprintf(stderr, "delcmt error 0\n"); 
    return -1;
  }
  while ( EOF != (char0 = fgetc(p_in))){
    switch(state){
    case NON_CMT:
      switch(char0){
      case '/':
        char1 = char0;
        state = CMT_SEMI_START;
        break;
      default :
        if(EOF == fputc(char0, p_out)){
          goto error_end;
        }
        state = NON_CMT;
        break;
      }
      break;
    case  CMT_SEMI_START:
      switch(char0){
      case '/':
        state = CPP_CMT;
        break;
      case '*':
        state = C_CMT;
        break;
      default:
        if(EOF == fputc(char1, p_out)){
          goto error_end;
        }
        if(EOF == fputc(char0, p_out)){
          goto error_end;
        }
        state = NON_CMT;
        break;
      }
      break;
    case CPP_CMT:
      switch(char0){
      case '\n':
        if(EOF == fputc(char0, p_out)){
          goto error_end;
        }
        state = NON_CMT;
        break;
      default:
        state = CPP_CMT;
        break;
      }
      break;
    case C_CMT:
      switch(char0){
      case '*':
        state = CMT_SEMI_END;
        break;
      default:
        state = C_CMT;
        break;
      }
      break;
    case CMT_SEMI_END:
      switch(char0){
      case '/':
        state = NON_CMT;
        break;
      default:
        state = C_CMT;
        break;
      }
      break;
    default:
      goto error_end;
    }
  }
 
  if(!feof(p_in)){
    goto error_end;
  }   fclose(p_in);
  fclose(p_out);   return 0;   error_end:   fclose(p_in);
  fclose(p_out);   fprintf(stderr, "delcmt error 1\n");
  return -1;
}

delcmt.hでは、「状態」を定義する定数を#defineするのと、関数の宣言をしているだけ。

#define NON_CMT        0
#define CMT_SEMI_START 1
#define CPP_CMT        2
#define C_CMT          3
#define CMT_SEMI_END   4

int delcmt(FILE *fp_in, FILE *fp_out);

中身の説明ですが、1文字ずつfgetcして、以下の5状態を遷移しつつ、非コメントの文字だけを出力しております。

  • コメント外の状態、
  • /が来てコメントが始まるかも知れない状態
  • /に引き続き/が来て、行末までコメントの状態
  • /に引き続き*が来て、コメントになった状態
  • コメント中に*が来てコメントが終わるかも知れない状態

拡張性を考えて、int delcmt(FILE*, FILE*)は、ファイルストリームを引数に受け取るようにしてあり、stdinでもstdoutでも実際のファイルでも、何でも受け付けられるようにしてあります。

なお、

/* コメント/*コメント*/コメント */

この様な入れ子のコメントには対応していません。この場合は、

/*コメント/*コメント*/本文本文*/

と解釈されます。

|

« coLinuxその3 | トップページ | ソースからコメントを削除する2 »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/207693/16044494

この記事へのトラックバック一覧です: ソースからコメントを削除する1:

« coLinuxその3 | トップページ | ソースからコメントを削除する2 »