コメントを抜き出すプログラム
Cのソースファイルの中からコメント(/* ・・・ */)だけを別ファイルに書き出すプログラムを作ろう.
新入社員への課題等でありそうな内容.「ソースファイルを1文字づつ読んで,コメントを見つけたかどうかのフラグを持って・・・」という作り方とは違うやり方を考えてみた.以下ソース.
/* 1: comment.c */
#include <stdio.h>
main(int argc,char *argv[])
{
FILE *comment=fopen(argv[1],"w");
FILE *source=fopen(argv[2],"r");
scan_comment(comment,source);
fclose(comment);
fclose(source);
}
int scan_comment(FILE *comment,FILE *source)
{
return in_function(comment,source);
}
int in_function(FILE *comment,FILE *source)
{
int c;
while((c=getc(source))!='/'&&c!='"'&&c!='\''&&c!=EOF){
}
switch(c){
case '/': /* 2: コメントが始まるのかも */
return begin_comment(comment,source);
break;
case '"': /* 3: 文字列.文字列の中では"/*"が出てきてもコメントではない */
return in_string(comment,source);
break;
case '\'': /* 4: 文字 */
return in_charactor(comment,source);
break;
default: /* 5: ファイルが終った */
return normal_end();
break;
}
}
int begin_comment(FILE *comment,FILE *source)
{
switch(getc(source)){
case '*': /* 6: '/'の次の文字が'*'だったらコメントの始まり */
return in_comment(comment,source);
break;
case '"': /* 7: '/'の次の文字が'"'だったら文字列.コメントではない */
return in_string(comment,source);
break;
case '\'': /* 8: '/'の次の文字が'\''だったら文字.コメントではない */
return in_charactor(comment,source);
break;
case EOF:
return normal_end();
break;
default:
return in_function(comment,source);
break;
}
}
int in_comment(FILE *comment,FILE *source)
{
int c;
while((c=getc(source))!='*'&&c!=EOF){
putc(c,comment);
}
return (c=='*')? end_comment(comment,source): abnormal_end();
/* 9: "/*"の後に続く文字列に'*'が出てきたらコメントが終るのかも
コメントが終らないでファイルが終ってはまずい */
}
int end_comment(FILE *comment,FILE *source)
{
int c=getc(source);
switch(c){
case '/': /* 10: コメント終了 */
return in_function(comment,source);
break;
case EOF:
return abnormal_end();
break;
default: /* 11: コメント継続 */
putc('*',comment);
putc(c,comment);
return in_comment(comment,source);
break;
}
}
int in_string(FILE *comment,FILE *source)
{
return not_comment_until_find_this('"',comment,source);
}
int in_charactor(FILE *comment,FILE *source)
{
return not_comment_until_find_this('\'',comment,source);
}
int not_comment_until_find_this(int mark,FILE *comment,FILE *source)
{
int c;
while((c=getc(source))!=mark&&c!=EOF){
if(c=='\\'){ /* 12: エスケープしていたら次の文字が'だろうと"だろうと無視して次へ */
getc(source);
}
}
return (c==mark)? in_function(comment,source): abnormal_end();
}
int normal_end()
{
return 1;
}
int abnormal_end()
{
return 0;
}
cygwinで動くgcc 3.4.4でコンパイルして実行してみた.
$ gcc comment.c
$ a comment.txt comment.c
comment.txtの内容は以下の通り.適当に改行を入れている.
1: comment.c 2: コメントが始まるのかも 3: 文字列.文字列の中では"/*"が出てきてもコメント
ではない 4: 文字 5: ファイルが終った 6: '/'の次の文字が'*'だったらコメントの始まり 7:
'/'の次の文字が'"'だったら文字列.コメントではない 8: '/'の次の文字が'"'だったら文字.コメ
ントではない 9: "/*"の後に続く文字列に'*'が出てきたらコメントが終るのかも
コメントが終らないでファイルが終ってはまずい 10: コメント終了 11: コメント継続 12: エス
ケープしていたら1文字無視して次へ