私はかつてこれを思いつきました。
perl -0777 -pe '
BEGIN{
$bs=qr{(?:\\|\?\?/)};
$lc=qr{(?:$bs\n|$bs\r\n?)}
}
s{
/$lc*\*.*?\*$lc*/
| /$lc*/(?:$lc|[^\r\n])*
| (
"(?:$bs$lc*.|.)*?"
| '\''$lc*(?:$bs$lc*(?:\?\?.|.))?(?:\?\?.|.)*?'\''
| \?\?'\''
| .[^'\''"/?]*
)
}{$1 eq "" ? " " : "$1"}exsg'
いくつかのコーナーケースを処理します。
コメントを削除すると、コードの意味を変更できることに注意してください(whileの1-/* comment */-1ように解析されます(コメントを削除した場合に取得します)はエラーになります)。コメントを完全に削除するのではなく、(ここで行っているように)コメントをスペース文字で置き換える方が適切です。1 - -11--1
上記は、いくつかのコーナーケースを含めようとするこの有効なANSI Cコードで適切に動作するはずです。
#include <stdio.h>
int main()
{
printf( "%d%s%c%c%c%c%c%s%s%d \ n"、
1-/ *コメント* /-1
/ \
*コメント* /
「/ *コメントではありません* /」、
/ *マルチライン
コメント* /
'"' / *コメント* /、 '"'、
'\' '、' "'/ *コメント* /、
'\
\
"'、/ *コメント* /
「\\
"/ *コメントではありません* /"、
"?? /" / *コメントではありません* / "、
'??' '+' "'/ *"コメント "* /);
0を返します。
}
これはこの出力を与えます:
#include <stdio.h>
int main()
{
printf( "%d%s%c%c%c%c%c%s%s%d \ n"、
1- -1
「/ *コメントではありません* /」、
'"'、 '"'、
'\' '、' "'、
'\
\
「 '、
「\\
"/ *コメントではありません* /"、
"?? /" / *コメントではありません* / "、
'??' '+' "');
0を返します。
}
両方とも、コンパイルおよび実行時に同じ出力を印刷します。
の出力と比較して、gcc -ansi -Eプリプロセッサがそれに対して何を行うかを確認できます。このコードは有効なC99またはC11コードでもありますがgcc、デフォルトでtrigraphsサポートを無効にしているためgcc、標準のような指定gcc -std=c99やオプションのgcc -std=c11追加を行わない限り機能しません-trigraphs。
このC99 / C11(非ANSI / C90)コードでも機能します。
//コメント
/ \
/コメント
//複数行\
コメント
「//コメントではありません」
(gcc -E/ gcc -std=c99 -E/ と比較gcc -std=c11 -E)
ANSI Cは// formofコメントをサポートしていません。//それ以外の場合はANSI Cでは有効ではないため、ここには表示されません。//ANSI Cに純粋に現れる可能性のある不自然なケース(そこに記載されているように、議論の残りの部分がおもしろいかもしれません)は、stringify演算子が使用されている場合です。
これは有効なANSI Cコードです。
#define s(x) #x
s(//not a comment)
そして、2004年の議論の時点で、gcc -ansi -E実際にそれを拡張しました"//not a comment"。ただし、今日gcc-5.4はエラーが返されるため、この種の構造を使用したCコードが多数見つかるとは思いません。
GNUにsed相当するものは次のようなものです。
lc='([\\%]\n|[\\%]\r\n?)'
sed -zE "
s/_/_u/g;s/!/_b/g;s/</_l/g;s/>/_r/g;s/:/_c/g;s/;/_s/g;s/@/_a/g;s/%/_p/g;
s@\?\?/@%@g;s@/$lc*\*@:&@g;s@\*$lc*/@;&@g
s:/$lc*/:@&:g;s/\?\?'/!/g
s#:/$lc*\*[^;]*;\*$lc*/|@/$lc*/$lc*|(\"([\\\\%]$lc*.|[^\\\\%\"])*\"|'$lc*([\\\\%]$lc*.)?[^\\\\%']*'|[^'\"@;:]+)#<\5>#g
s/<>/ /g;s/!/??'/g;s@%@??/@g;s/[<>@:;]//g
s/_p/%/g;s/_a/@/g;s/_s/;/g;s/_c/:/g;s/_r/>/g;s/_l/</g;s/_b/!/g;s/_u/_/g"
GNU sedが古すぎてサポートできない場合、-Eまたは-z最初の行を次のように置き換えることができます。
sed -r ":1;\$!{N;b1}