Una volta ho pensato a questo che possiamo affinare a:
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'
per gestire alcuni altri casi angolari.
Si noti che se si rimuove un commento, è possibile modificare il significato del codice ( 1-/* comment */-1
analizzato come 1 - -1
while 1--1
(che si otterrebbe se si rimuovesse il commento) si darebbe un errore). È meglio sostituire il commento con un carattere spaziale (come facciamo qui) invece di rimuoverlo completamente.
Quanto sopra dovrebbe funzionare correttamente su questo codice ANSI C valido, ad esempio, che tenta di includere alcuni casi angolari:
#include <stdio.h>
int main ()
{
printf ("% d% s% c% c% c% c% c% s% s% d \ n",
1 - / * commento * / - 1,
/ \
* commento * /
"/ * non un commento * /",
/ * multilinea
commento * /
'"' / * comment * /, '"',
'\' ',' "'/ * comment * /,
'\
\
"', / * commento * /
"\\
"/ * non un commento * /",
"?? /" / * non un commento * / ",
'??' '+' "'/ *" comment "* /);
ritorna 0;
}
Che dà questo risultato:
#include <stdio.h>
int main ()
{
printf ("% d% s% c% c% c% c% c% s% s% d \ n",
1- -1,
"/ * non un commento * /",
'"', '"',
'\' ',' "',
'\
\
"',
"\\
"/ * non un commento * /",
"?? /" / * non un commento * / ",
'??' '+' "');
ritorna 0;
}
Entrambi stampano lo stesso output quando vengono compilati ed eseguiti.
Puoi confrontare con l'output di gcc -ansi -E
per vedere cosa farebbe il pre-processore su di esso. Tale codice è anche un codice C99 o C11 valido, tuttavia gcc
disabilita il supporto trigraph per impostazione predefinita, quindi non funzionerà a gcc
meno che non si specifichi lo standard gcc -std=c99
o gcc -std=c11
o si aggiunga l' -trigraphs
opzione).
Funziona anche con questo codice C99 / C11 (non ANSI / C90):
// commento
/ \
/ commento
// multilinea \
commento
"// non un commento"
(confronta con gcc -E
/ gcc -std=c99 -E
/ gcc -std=c11 -E
)
ANSI C non supportava il // form
commento. //
non è altrimenti valido in ANSI C quindi non apparirebbe lì. Un caso forzato in cui //
potrebbe effettivamente apparire in ANSI C (come notato qui , e potresti trovare interessante il resto della discussione) è quando l' operatore stringify è in uso.
Questo è un codice ANSI C valido:
#define s(x) #x
s(//not a comment)
E al momento della discussione del 2004, l' gcc -ansi -E
aveva davvero ampliata "//not a comment"
. Tuttavia oggi gcc-5.4
restituisce un errore, quindi dubito che troveremo molto codice C usando questo tipo di costrutto.
L' sed
equivalente GNU potrebbe essere qualcosa del tipo:
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 la tua GNU sed
è troppo vecchia per supportare -E
o -z
, puoi sostituire la prima riga con:
sed -r ":1;\$!{N;b1}