Una vez se me ocurrió esto 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 manejar algunos casos más de esquina.
Tenga en cuenta que si elimina un comentario, podría cambiar el significado del código ( 1-/* comment */-1
se analiza como 1 - -1
while 1--1
(que obtendría si eliminara el comentario) le daría un error). Es mejor reemplazar el comentario con un carácter de espacio (como lo hacemos aquí) en lugar de eliminarlo por completo.
Lo anterior debería funcionar correctamente en este código ANSI C válido, por ejemplo, que intenta incluir algunos casos de esquina:
#include <stdio.h>
int main ()
{
printf ("% d% s% c% c% c% c% c% s% s% d \ n",
1 - / * comentario * / - 1,
/ \
* comentario * /
"/ * no es un comentario * /",
/ * multilínea
comentario * /
'"' / * comentario * /, '"',
'\' ',' "'/ * comentario * /,
'\
\
"', / * comentario * /
"\\
"/ * no es un comentario * /",
"?? /" / * no es un comentario * / ",
'??' '+' "'/ *" comentario "* /);
devuelve 0;
}
Lo que da esta salida:
#include <stdio.h>
int main ()
{
printf ("% d% s% c% c% c% c% c% s% s% d \ n",
1- -1,
"/ * no es un comentario * /",
'"', '"',
'\' ',' "',
'\
\
"',
"\\
"/ * no es un comentario * /",
"?? /" / * no es un comentario * / ",
'??' '+' "');
devuelve 0;
}
Ambos imprimen el mismo resultado cuando se compilan y se ejecutan.
Puede comparar con la salida de gcc -ansi -E
para ver qué haría el preprocesador en él. Ese código es también válido o código C99 C11, sin embargo gcc
desactiva trigrafos apoyan de forma predeterminada por lo que no va a funcionar con gcc
menos que especifique el estándar como gcc -std=c99
o gcc -std=c11
o agregar la -trigraphs
opción).
También funciona en este código C99 / C11 (no ANSI / C90):
// comentario
/ \
/ comentario
// multilínea \
comentario
"// no es un comentario"
(comparar con gcc -E
/ gcc -std=c99 -E
/ gcc -std=c11 -E
)
ANSI C no apoyó el // form
comentario. //
de lo contrario no es válido en ANSI C, por lo que no aparecería allí. Un caso artificial en el que //
puede aparecer genuinamente en ANSI C (como se señala allí , y puede encontrar interesante el resto de la discusión) es cuando el operador stringify está en uso.
Este es un código ANSI C válido:
#define s(x) #x
s(//not a comment)
Y en el momento de la discusión en 2004, de gcc -ansi -E
hecho lo expandió a "//not a comment"
. Sin embargo, hoy gcc-5.4
devuelve un error, por lo que dudo que encontremos mucho código C con este tipo de construcción.
El sed
equivalente de GNU podría 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"
Si su GNU sed
es demasiado antigua para admitir -E
o -z
, puede reemplazar la primera línea con:
sed -r ":1;\$!{N;b1}