Certa vez, inventei isso 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 de canto.
Observe que se você remover um comentário, poderá alterar o significado do código ( 1-/* comment */-1
é analisado como 1 - -1
while 1--1
(que você obteria se removesse o comentário) causaria um erro). É melhor substituir o comentário por um caractere de espaço (como fazemos aqui) em vez de removê-lo completamente.
O exemplo acima deve funcionar corretamente nesse código ANSI C válido, por exemplo, que tenta incluir alguns casos de canto:
#include <stdio.h>
int main ()
{
printf ("% d% s% c% c% c% c% c% s% s% d \ n",
1 - / * comentário * / - 1,
/ \
* Comente */
"/ * não é um comentário * /",
/ * multiline
Comente */
'"' /* Comente */ , '"',
'\'','"'/* Comente */,
'\
\
"', /* Comente */
"\\
"/ * não é um comentário * /",
"?? /" / * não é um comentário * / ",
'??' '+' "'/ *" comentário "* /);
retornar 0;
}
O que fornece esta saída:
#include <stdio.h>
int main ()
{
printf ("% d% s% c% c% c% c% c% s% s% d \ n",
1- -1,
"/ * não é um comentário * /",
'"', '"'
'\' ',' "',
'\
\
"'
"\\
"/ * não é um comentário * /",
"?? /" / * não é um comentário * / ",
'??' '+' "');
retornar 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 é um código C99 ou C11 válido, no entanto, gcc
desabilita o suporte a trigrafs por padrão, para que não funcione, a gcc
menos que você especifique o padrão como gcc -std=c99
ou gcc -std=c11
ou adicione a -trigraphs
opção).
Também funciona neste código C99 / C11 (não-ANSI / C90):
// Comente
/ \
/ Comente
// multiline \
Comente
"// não é um comentário"
(compare com gcc -E
/ gcc -std=c99 -E
/ gcc -std=c11 -E
)
O ANSI C não suporta o // form
comentário. //
não é válido de outra maneira no ANSI C, portanto, não apareceria lá. Um caso artificial em que //
pode realmente aparecer no ANSI C (como observado aqui , e você pode achar o restante da discussão interessante) é quando o operador stringify está em uso.
Este é um código ANSI C válido:
#define s(x) #x
s(//not a comment)
E na época da discussão em 2004, de gcc -ansi -E
fato a expandiu para "//not a comment"
. No entanto, hoje, gcc-5.4
retorna um erro, então duvido que encontraremos muito código C usando esse tipo de construção.
O sed
equivalente 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*.)?[^\\\\%']*'|[^'\"@;:]+)#<\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"
Se seu GNU sed
é muito antigo para suportar -E
ou -z
, você pode substituir a primeira linha por:
sed -r ":1;\$!{N;b1}