我曾经想出过这一点,我们可以对其进行完善:
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'
处理更多的极端情况。
请注意,如果删除注释,则可以更改代码的含义(1-/* comment */-1
解析的方式如1 - -1
while 1--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不支持// form
comment。//
在ANSI C中无效,因此不会出现在ANSI C中。一个做作的情况下//
可以真正出现在ANSI C(为指出存在的,你可能会发现有趣的讨论的其余部分)是当字符串化操作者在使用中。
这是有效的ANSI C代码:
#define s(x) #x
s(//not a comment)
在2004年的讨论中,gcc -ansi -E
确实将其扩展到"//not a comment"
。但是今天,它gcc-5.4
返回了一个错误,所以我怀疑我们会发现使用这种结构的很多C代码。
sed
相当于GNU的可能是:
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}