Une fois, je suis venu avec ce que nous pouvons affiner:
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'
pour gérer quelques autres cas d'angle.
Notez que si vous supprimez un commentaire, vous pouvez changer la signification du code ( 1-/* comment */-1
est analysé comme 1 - -1
while 1--1
(que vous obtiendriez si vous supprimiez le commentaire) vous donnerait une erreur). Il est préférable de remplacer le commentaire par un caractère espace (comme nous le faisons ici) au lieu de le supprimer complètement.
Ce qui précède devrait fonctionner correctement sur ce code C ANSI valide par exemple qui essaie d'inclure quelques cas d'angle:
#include <stdio.h>
int main()
{
printf ("% d% s% c% c% c% c% c% s% s% d \ n",
1 - / * commentaire * / - 1,
/ \
* commentaire * /
"/ * pas un commentaire * /",
/ * multiligne
commentaire * /
'"' / * commentaire * /, '"',
'\' ',' "'/ * comment * /,
'\
\
"', / * commentaire * /
"\\
"/ * pas un commentaire * /",
"?? /" / * pas un commentaire * / ",
'??' '+' "'/ *" comment "* /);
retourner 0;
}
Ce qui donne cette sortie:
#include <stdio.h>
int main()
{
printf ("% d% s% c% c% c% c% c% s% s% d \ n",
1- -1,
"/ * pas un commentaire * /",
'"', '"',
'\' ',' "',
'\
\
"',
"\\
"/ * pas un commentaire * /",
"?? /" / * pas un commentaire * / ",
'??' '+' "');
retourner 0;
}
Les deux affichent la même sortie une fois compilés et exécutés.
Vous pouvez comparer avec la sortie de gcc -ansi -E
pour voir ce que ferait le pré-processeur. Ce code est également un code C99 ou C11 valide, mais gcc
désactive la prise en charge des trigraphes par défaut, de sorte qu'il ne fonctionnera pas gcc
sauf si vous spécifiez la norme comme gcc -std=c99
ou gcc -std=c11
ou ajoutez l' -trigraphs
option).
Il fonctionne également sur ce code C99 / C11 (non-ANSI / C90):
// commentaire
/ \
/ commentaire
// multiligne \
commentaire
"// pas un commentaire"
(comparer avec gcc -E
/ gcc -std=c99 -E
/ gcc -std=c11 -E
)
ANSI C n'a pas soutenu le // form
commentaire. //
n'est pas par ailleurs valide dans ANSI C, donc n'y apparaîtrait pas. Un cas artificiel où //
peut véritablement apparaître dans ANSI C (comme indiqué ici , et vous pouvez trouver le reste de la discussion intéressant) est lorsque l' opérateur stringify est utilisé.
Il s'agit d'un code ANSI C valide:
#define s(x) #x
s(//not a comment)
Et au moment de la discussion en 2004, gcc -ansi -E
il a effectivement été étendu à "//not a comment"
. Cependant aujourd'hui, gcc-5.4
renvoie une erreur dessus, donc je doute que nous trouvions beaucoup de code C en utilisant ce type de construction.
L' sed
équivalent GNU pourrait être quelque chose comme:
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 votre GNU sed
est trop ancien pour supporter -E
ou -z
, vous pouvez remplacer la première ligne par:
sed -r ":1;\$!{N;b1}