ソースからコメントを削除する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 4int delcmt(FILE *fp_in, FILE *fp_out);
中身の説明ですが、1文字ずつfgetcして、以下の5状態を遷移しつつ、非コメントの文字だけを出力しております。
- コメント外の状態、
- /が来てコメントが始まるかも知れない状態
- /に引き続き/が来て、行末までコメントの状態
- /に引き続き*が来て、コメントになった状態
- コメント中に*が来てコメントが終わるかも知れない状態
拡張性を考えて、int delcmt(FILE*, FILE*)は、ファイルストリームを引数に受け取るようにしてあり、stdinでもstdoutでも実際のファイルでも、何でも受け付けられるようにしてあります。
なお、
/* コメント/*コメント*/コメント */
この様な入れ子のコメントには対応していません。この場合は、
/*コメント/*コメント*/本文本文*/
と解釈されます。
| 固定リンク
この記事へのコメントは終了しました。


コメント