Kiedyś wpadłem na pomysł, który możemy udoskonalić:
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'
aby obsłużyć jeszcze kilka skrzynek narożnych
Zauważ, że jeśli usuniesz komentarz, możesz zmienić znaczenie kodu ( 1-/* comment */-1
parsowane jak 1 - -1
podczas while 1--1
(które uzyskasz , jeśli usuniesz komentarz) spowoduje błąd). Lepiej zastąpić komentarz spacją (tak jak tutaj), zamiast całkowicie go usunąć.
Powyższe powinno działać poprawnie na tym poprawnym kodzie ANSI C, na przykład, który próbuje uwzględnić kilka przypadków narożnych:
#include <stdio.h>
int main ()
{
printf ("% d% s% c% c% c% c% c% s% s% d \ n",
1 - / * komentarz * / - 1,
/ \
* komentarz */
„/ * nie jest komentarzem * /”,
/ * multiline
komentarz */
'"' /* komentarz */ , '"',
'\'','"'/* komentarz */,
„\
\
"', /* komentarz */
„\\
„/ * nie jest komentarzem * /”,
„?? /” / * not a comment * / ”,
„??” „+” „” / * „komentarz” * /);
zwraca 0;
}
Co daje ten wynik:
#include <stdio.h>
int main ()
{
printf ("% d% s% c% c% c% c% c% s% s% d \ n",
1- -1
„/ * nie jest komentarzem * /”,
„” „” „”
„\”, „”
„\
\
„”,
„\\
„/ * nie jest komentarzem * /”,
„?? /” / * not a comment * / ”,
„??” „+” „);
zwraca 0;
}
Oba drukują ten sam wynik po kompilacji i uruchomieniu.
Możesz porównać z wyjściem, gcc -ansi -E
aby zobaczyć, co zrobiłby na nim procesor wstępny. Ten kod jest również prawidłowym kodem C99 lub C11, jednak gcc
domyślnie wyłącza obsługę trigrafów, więc nie będzie działać, gcc
chyba że określisz standard, gcc -std=c99
lub gcc -std=c11
lub dodasz -trigraphs
opcję).
Działa również z tym kodem C99 / C11 (nie ANSI / C90):
// komentarz
/ \
/ komentarz
// multiline \
komentarz
„// bez komentarza”
(porównaj z gcc -E
/ gcc -std=c99 -E
/ gcc -std=c11 -E
)
ANSI C nie obsługiwał // form
komentarza. //
nie jest inaczej ważne w ANSI C, więc nie pojawi się tam. Jednym z wymyślonych przypadków, w których //
może rzeczywiście pojawić się w ANSI C (jak tam wspomniano , a resztę dyskusji może okazać się interesująca), jest użycie operatora strunizacji .
To jest poprawny kod ANSI C:
#define s(x) #x
s(//not a comment)
I w czasie dyskusji w 2004 r. gcc -ansi -E
Rzeczywiście ją rozszerzyłem "//not a comment"
. Jednak dzisiaj gcc-5.4
zwraca błąd, więc wątpię, abyśmy znaleźli dużo kodu C przy użyciu tego rodzaju konstrukcji.
Odpowiednikiem GNU sed
może być coś takiego:
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"
Jeśli GNU sed
jest zbyt stary, by wspierać -E
lub -z
można wymienić pierwszą linię z:
sed -r ":1;\$!{N;b1}