c コードを使用して、ac ファイルからコメントと文字列を削除しようとしています。例のコメントに固執します。私はスライド式の窓を持っているので、いつでもキャラクターだけを持っていn
ますn-1
。whiles
可能であればネストを使用しないアルゴリズムを見つけようとしていますがgetchar
、入力を完了するにはしばらく時間が必要です。私の最初の考えは、 while を介して find when n=* and (n-1)=/
then while through until でしn=/ and (n-1)=*
たが、これが whiles をネストしていることを考えると、非効率的だと思います。必要に応じてこの方法で行うことができますが、誰かがより良い解決策を持っているかどうか疑問に思っていました.
3 に答える
2
1 つのループで記述されたアルゴリズムは次のwhile
ようになります。
while ((c = getchar()) != EOF)
{
... // looking at the byte that was just read
if (...) // the symbol is not inside a comment
{
putchar(c);
}
}
入力char
がコメントに属するかどうかを判断するには、ステート マシンを使用できます。次の例では、4 つの状態があります。次の状態に移動するための規則もあります。
int state = 0;
int next_state;
while ((c = getchar()) != EOF)
{
switch (state)
{
case 0: next_state = (c == '/' ? 1 : 0); break;
case 1: next_state = (c == '*' ? 2 : c == '/' ? 1 : 0); break;
case 2: next_state = (c == '*' ? 3 : 2); break;
case 3: next_state = (c == '/' ? 0 : c == '*' ? 3 : 2); break;
default: next_state = state; // will never happen
}
if (state == 1 && next_state == 0)
{
putchar('/'); // for correct output when a slash is not followed by a star
}
if (state == 0 && next_state == 0)
{
putchar(c);
}
state = next_state;
}
上記の例は非常に単純です/*
。C 文字列のような非コメント コンテキストでは正しく動作しません。//
コメントなどはサポートしていません。
于 2013-04-18T16:02:16.050 に答える
1
バッファに 2 文字と while ループを 1 つだけ使用したいので、(テキストをスキップするかどうかにかかわらず) 状態を追跡するために 3 番目の文字を使用することをお勧めします。ロジックを説明するインライン コメントを使用して、テスト プログラムを作成しました。
// Program to strip comments and strings from a C file
//
// Build:
// gcc -o strip-comments strip-comments.c
//
// Test:
// ./strip-comments strip-comments.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
/* The following is a block of strings, and comments for testing
* the code.
*/
/* test if three comments *//* chained together */// will be removed.
static int value = 128 /* test comment within valid code *// 2;
const char * test1 = "This is a test of \" processing"; /* testing inline comment */
const char * test2 = "this is a test of \n within strings."; // testing inline comment
// this is a the last test
int strip_c_code(FILE * in, FILE * out)
{
char buff[2];
char skipping;
skipping = '\0';
buff[0] = '\0';
buff[1] = '\0';
// loop through the file
while((buff[0] = fgetc(in)) != EOF)
{
// checking for start of comment or string block
if (!(skipping))
{
// start skipping in "//" comments
if ((buff[1] == '/') && (buff[0] == '/'))
skipping = '/';
// start skipping in "/*" comments
else if ((buff[1] == '/') && (buff[0] == '*'))
skipping = '*';
// start skipping at start of strings, but not character assignments
else if ( ((buff[1] != '\'') && (buff[0] == '"')) &&
((buff[1] != '\\') && (buff[0] == '"')) )
{
fputc(buff[1], out);
skipping = '"';
};
// clear buffer so that processed characters are not interpreted as
// end of skip characters.
if ((skipping))
{
buff[0] = '\0';
buff[1] = '\0';
};
};
// check for characters which terminate skip block
switch(skipping)
{
// if skipping "//" comments, look for new line
case '/':
if (buff[1] == '\n')
skipping = '\0';
break;
// if skipping "/*" comments, look for "*/" terminating string
case '*':
if ((buff[1] == '*') && (buff[0] == '/'))
{
buff[0] = '\0';
buff[1] = '\0';
skipping = '\0';
};
break;
// if skipping strings, look for terminating '"' character
case '"':
if ((buff[1] != '\\') && (buff[0] == '"'))
{
skipping = '\0';
buff[0] = '\0';
buff[1] = '\0';
fprintf(out, "NULL"); // replace string with NULL
};
break;
default:
break;
};
// if not skipping, write character out
if ( (!(skipping)) && ((buff[1])) )
fputc(buff[1], out);
// shift new character to old character position
buff[1] = buff[0];
};
// verify that the comment or string was terminated properly
if ((skipping))
{
fprintf(stderr, "Unterminated comment or string\n");
return(-1);
};
// write last character
fputc(buff[1], out);
return(0);
}
int main(int argc, char * argv[])
{
FILE * fs;
if (argc != 2)
{
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return(1);
};
if ((fs = fopen(argv[1], "r")) == NULL)
{
perror("fopen()");
return(1);
};
strip_c_code(fs, stdout);
fclose(fs);
return(0);
}
/* end of source file */
ダウンロードとコンパイルを簡単にするために、このコードを Github にも投稿しました。
于 2013-04-18T23:53:46.980 に答える