これは、必要な変換を実行するCで記述された簡単にテストされたフィルターです。このフィルターが何をするかについてのいくつかのコメントは、正規表現で処理することが不可能ではないにしても難しいです:
- 引用符で囲まれたコメントのようなシーケンスは無視されます(コメントではないため)
- 変換中のC99コメントにC89コメントを開始または終了するものが含まれている場合、そのシーケンスが変更されるため、ネストされたコメントやコメントの途中で終了することはありません(ネストされた、
/*
または*/
に変更され/+
ます/|
)。これが必要かどうかはわかりませんでした(必要ない場合は、簡単に削除できるはずです)
- 上記のネストされたコメントの変更は、変換中のC99コメントでのみ発生します。すでにC89スタイルになっているコメントの内容は変更されません。
- トリグラフまたはダイグラフは処理しません(これにより、トリグラフで開始されるエスケープシーケンスまたは行末の継続が欠落する可能性があるだけだと思います
??/
)。
もちろん、目的に適しているかどうかを判断するには、独自のテストを実行する必要があります。
#include <stdio.h>
char* a = " this is /* a test of \" junk // embedded in a '\' string";
char* b = "it should be left alone//";
// comment /* that should ***//// be converted.
/* leave this alone*/// but fix this one
// and "leave these \' \" quotes in a comment alone*
/**** and these '\' too //
*/
enum states {
state_normal,
state_double_quote,
state_single_quote,
state_c89_comment,
state_c99_comment
};
enum states current_state = state_normal;
void handle_char( char ch)
{
static char last_ch = 0;
switch (current_state) {
case state_normal:
if ((last_ch == '/') && (ch == '/')) {
putchar( '*'); /* NOTE: changing to C89 style comment */
current_state = state_c99_comment;
}
else if ((last_ch == '/') && (ch == '*')) {
putchar( ch);
current_state = state_c89_comment;
}
else if (ch == '\"') {
putchar( ch);
current_state = state_double_quote;
}
else if (ch == '\'') {
putchar( ch);
current_state = state_single_quote;
}
else {
putchar( ch);
}
break;
case state_double_quote:
if ((last_ch == '\\') && (ch == '\\')) {
/* we want to output this \\ escaped sequence, but we */
/* don't want to 'remember' the current backslash - */
/* otherwise we'll mistakenly treat the next character*/
/* as being escaped */
putchar( ch);
ch = 0;
}
else if ((ch == '\"') && (last_ch != '\\')) {
putchar( ch);
current_state = state_normal;
}
else {
putchar( ch);
}
break;
case state_single_quote:
if ((last_ch == '\\') && (ch == '\\')) {
/* we want to output this \\ escaped sequence, but we */
/* don't want to 'remember' the current backslash - */
/* otherwise we'll mistakenly treat the next character*/
/* as being escaped */
putchar( ch);
ch = 0;
}
else if ((ch == '\'') && (last_ch != '\\')) {
putchar( ch);
current_state = state_normal;
}
else {
putchar( ch);
}
break;
case state_c89_comment:
if ((last_ch == '*') && (ch == '/')) {
putchar( ch);
ch = 0; /* 'forget' the slash so it doesn't affect a possible slash that immediately follows */
current_state = state_normal;
}
else {
putchar( ch);
}
break;
case state_c99_comment:
if ((last_ch == '/') && (ch == '*')) {
/* we want to change any slash-star sequences inside */
/* what was a C99 comment to something else to avoid */
/* nested comments */
putchar( '+');
}
else if ((last_ch == '*') && (ch == '/')) {
/* similarly for star-slash sequences inside */
/* what was a C99 comment */
putchar( '|');
}
else if (ch == '\n') {
puts( "*/");
current_state = state_normal;
}
else {
putchar( ch);
}
break;
}
last_ch = ch;
}
int main(void)
{
int c;
while ((c = getchar()) != EOF) {
handle_char( c);
}
return 0;
}
いくつかの贅沢な解説:何年も前に、私が働いていた店は、当時使用していたコンパイラに問題がなかったとしても、コードが必要になる可能性があるという理由で、C99スタイルのコメントを禁止するコーディング標準を課したいと考えていましたそれらをサポートしていないコンパイラに移植されました。私(および他の人)は、その可能性は本質的に存在しないほど遠いものであり、たとえそれが起こったとしても、コメントを互換性のあるものにするための変換ルーチンを簡単に書くことができると首尾よく主張しました。C99 /C++スタイルのコメントの使用が許可されました。
私は今、私の誓いが成就したと考えており、私にかけられたかもしれないどんな呪いも解き放たれると考えています。