Uma vez eu criei este que podemos refinar:
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'
para lidar com mais alguns casos importantes.
Se você remover um comentário, poderá alterar o significado do código ( 1-/* comment */-1
é analisado como 1 - -1
enquanto 1--1
(o que você obteria se removesse o comentário) lhe daria um erro). É melhor substituir o comentário por um caractere de espaço (como fazemos aqui) em vez de removê-lo completamente.
O acima deve funcionar corretamente neste código ANSI C válido, por exemplo, que tenta incluir alguns casos:
#include <stdio.h>
int main()
{
printf("%d %s %c%c%c%c%c %s %s %d\n",
1-/* comment */-1,
/\
* comment */
"/* not a comment */",
/* multiline
comment */
'"' /* comment */ , '"',
'\'','"'/* comment */,
'\
\
"', /* comment */
"\
" /* not a comment */ ",
"??/" /* not a comment */ ",
'??''+'"' /* "comment" */);
return 0;
}
O que dá esta saída:
#include <stdio.h>
int main()
{
printf("%d %s %c%c%c%c%c %s %s %d\n",
1- -1,
"/* not a comment */",
'"' , '"',
'\'','"' ,
'\
\
"',
"\
" /* not a comment */ ",
"??/" /* not a comment */ ",
'??''+'"' );
return 0;
}
Ambos imprimem a mesma saída quando compilados e executados.
Você pode comparar com a saída de gcc -ansi -E
para ver o que o pré-processador faria nele. Esse código também é válido para o código C99 ou C11, no entanto gcc
desativa o suporte a trigraphs por padrão para não funcionar com gcc
, a menos que você especifique o padrão como gcc -std=c99
ou gcc -std=c11
ou adicione a opção -trigraphs
) .
Também funciona neste código C99 / C11 (não-ANSI / C90):
// comment
/\
/ comment
// multiline\
comment
"// not a comment"
(compare com gcc -E
/ gcc -std=c99 -E
/ gcc -std=c11 -E
)
ANSI C não suportou o // form
de comentários. //
não é válido de outra forma no ANSI C, portanto, não apareceria lá. Um caso planejado em que //
pode realmente aparecer em ANSI C (conforme observado há , e você pode achar interessante o resto da discussão) é quando o operador stringify está em uso.
Este é um código ANSI C válido:
#define s(x) #x
s(//not a comment)
E no momento da discussão em 2004, gcc -ansi -E
de fato expandiu para "//not a comment"
. No entanto, hoje em dia, gcc-5.4
retorna um erro, então duvido que encontremos muito código C usando esse tipo de construção.
O equivalente sed
do GNU pode ser algo como:
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*.)?[^\\%']*'|[^'\"@;:]+)#<>#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"
Se o seu GNU sed
for muito antigo para suportar -E
ou -z
, você poderá substituir a primeira linha por:
sed -r ":1;\$!{N;b1}