Jak ogólnie traktuje się komentarze w językach programowania i znacznikach? Piszę parser dla jakiegoś niestandardowego języka znaczników i chcę przestrzegać zasady najmniejszego zaskoczenia , więc staram się ustalić ogólną konwencję.
Na przykład, czy komentarz osadzony w tokenie powinien „zakłócać” token, czy nie? Zasadniczo jest coś takiego:
Sys/* comment */tem.out.println()
ważny?
Ponadto, jeśli język jest wrażliwy na nowe wiersze, a komentarz obejmuje nowy wiersz, czy należy wziąć pod uwagę nowy wiersz, czy nie?
stuff stuff /* this is comment
this is still comment */more stuff
być traktowanym jak
stuff stuff more stuff
lub
stuff stuff
more stuff
?
Wiem, co robi kilka konkretnych języków, nie szukam też opinii, ale szukam odpowiedzi na pytanie: czy istnieje ogólny konsensus, czego można się spodziewać po narzutach i nowych liniach?
Mój szczególny kontekst to znaczniki typu wiki.
Odpowiedzi:
Zazwyczaj komentarze są skanowane (i odrzucane) w ramach procesu tokenizacji, ale przed analizą. Komentarz działa jak separator tokenów, nawet jeśli nie ma wokół niego białych znaków.
Jak zauważyłeś, specyfikacja C wyraźnie stwierdza, że komentarze są zastępowane pojedynczą spacją. Jest to jednak tylko specyfikacja, ponieważ parser w świecie rzeczywistym niczego nie zastąpi, a jedynie skanuje i odrzuca komentarz w taki sam sposób, jak skanuje i odrzuca białe znaki. Ale wyjaśnia w prosty sposób, że komentarz rozdziela tokeny w taki sam sposób, jak spacja.
Treść komentarzy jest ignorowana, więc łamanie wiersza w komentarzach wielowierszowych nie ma wpływu. Języki wrażliwe na podział wiersza (Python i Visual Basic) zwykle nie mają komentarzy wielowierszowych, ale JavaScript jest jednym wyjątkiem. Na przykład:
Jest równa
nie
Komentarze jednowierszowe zachowują podział wiersza, tj
jest równa
nie
Ponieważ komentarze są skanowane, ale nie analizowane, zwykle nie zagnieżdżają się. Więc
to błąd składniowy, ponieważ komentarz jest otwierany przez pierwszy
/*
i zamykany przez pierwszy*/
źródło
/* like this */
) są uważane za równe pojedynczej spacji, a komentarze zakończone EOL (// like this
) w pustej linii.(define x #| this is #| a sub-comment |# the main comment |# 3) x
plony3
.Aby odpowiedzieć na pytanie:
Powiedziałbym, że nikt nie spodziewałby się, że komentarz osadzony w tokenie będzie zgodny z prawem.
Zasadniczo komentarze należy traktować tak samo jak białe znaki. Każde miejsce, które może mieć obce białe znaki, powinno mieć również możliwość umieszczenia komentarza. Jedynym wyjątkiem byłyby ciągi znaków:
Wspieranie komentarzy wewnątrz łańcuchów byłoby dziwne, a ucieczka przed nimi byłaby nużąca!
źródło
Hello /* world*/!
zamiast tłumić ograniczniki komentarzy. Witamy także w Programistach!W językach niewrażliwych na spacje ignorowane znaki (tj. Białe spacje lub te, które są częścią komentarza) ograniczają tokeny.
Na przykład
Sys tem
są dwa tokeny, podczas gdySystem
jeden. Przydatność tego może być bardziej widoczna, jeśli porównasz,new Foo()
anewFoo()
jeden z nich zbuduje instancję,Foo
podczas gdy inne wywołanianewFoo
.Komentarze mogą odgrywać taką samą rolę jak ciąg białych znaków, np.
new/**/Foo()
Działa tak samo jaknew Foo()
. Oczywiście może to być bardziej skomplikowane, npnew /**/ /**/ Foo()
.Technicznie powinno być możliwe zezwolenie na komentarze w ramach identyfikatorów, ale wątpię, aby było to szczególnie praktyczne.
A co z językami wrażliwymi na białe znaki?
Przychodzi mi na myśl Python i ma bardzo prostą odpowiedź: brak komentarzy blokowych. Zaczynasz komentarz od,
#
a następnie parser działa dokładnie tak, jakby reszta linii nie istniała, ale była tylko nową linią.W przeciwieństwie do tego, Jade pozwala na komentarze do bloku , gdzie blok kończy się, gdy wrócisz do tego samego poziomu wcięcia. Przykład:
Więc w tym królestwie nie powiedziałbym, że można powiedzieć, jak zwykle się sprawy załatwiają. Wydaje się, że wspólną cechą jest to, że komentarz zawsze kończy się końcem wiersza, co oznacza, że wszystkie komentarze działają dokładnie tak samo jak nowe wiersze.
źródło
W przeszłości komentarze zamieniałem w pojedynczy token w ramach analizy leksykalnej. To samo dotyczy ciągów znaków. Stamtąd życie jest łatwe.
W konkretnym przypadku ostatniego kompilatora, który zbudowałem, reguła Escape jest przekazywana do procedury analizy najwyższego poziomu. Reguła zmiany znaczenia jest używana do obsługi tokenów, takich jak tokeny komentarza zgodne z podstawową gramatyką. Ogólnie rzecz biorąc, te żetony zostały odrzucone.
Konsekwencją zrobienia tego w ten sposób jest to, że w przykładzie zamieszczonym z komentarzem pośrodku identyfikatora identyfikator nie byłby pojedynczym identyfikatorem - jest to oczekiwane zachowanie we wszystkich językach (z pamięci), z którymi pracowałem .
Przypadek komentarza w ciągu powinien być domyślnie rozpatrzony przez analizę leksykalną. Reguły do obsługi ciągu nie są zainteresowane komentarzami, dlatego komentarz jest traktowany jako treść ciągu. To samo dotyczy ciągu (lub literału cytowanego) w komentarzu - ciąg jest częścią komentarza, który jest jawnie pojedynczym tokenem; zasady przetwarzania komentarza nie są zainteresowane ciągami.
Mam nadzieję, że to ma sens / pomaga.
źródło
console.log(/*a comment containing "quotes" is possible*/ "and a string containing /*slash-star, star-slash*/ is possible")
, gdzie w komentarzu są cytaty i składnia komentarza w łańcuchu, to skąd lexer wiedziałby, aby poprawnie go tokenizować? Czy możesz zredagować swoją odpowiedź, podając ogólny opis tych przypadków?To zależy od celu twojego parsera. Jeśli napiszesz analizator składni, aby zbudować drzewo analizy do kompilacji, wówczas komentarz nie ma wartości semantycznej oprócz potencjalnie oddzielających tokenów (np. Metoda / komentarz / (/ komentarz /)). W tym przypadku jest traktowane jak spacje.
Jeśli twój parser jest częścią transpilatora tłumaczącego jeden język źródłowy na inny język źródłowy lub jeśli twój parser jest preprocesorem pobierającym jednostkę kompilacyjną w języku źródłowym, analizującym go, modyfikującym go i zapisującym zmodyfikowaną wersję z powrotem w tym samym języku źródłowym, komentarze jak wszystko inne staje się bardzo ważne.
Również jeśli masz meta informacje w komentarzach, a szczególnie zależy ci na komentarzach, takich jak przy generowaniu dokumentacji API, tak jak robi to JavaDoc, komentarze są nagle bardzo ważne.
Tutaj komentarze są często dołączane do samych tokenów. Jeśli znajdziesz komentarz, dołącz go jako komentarz tokena. Ponieważ token może mieć wiele tokenów przed i po, ponownie zależy od celu obsługi tych komentarzy.
Pomysł dodawania adnotacji do tokenów nieskomentujących za pomocą komentarzy polega na całkowitym usunięciu komentarzy z gramatyki.
Kiedy już masz parsowane drzewo, niektóre AST zaczynają rozpakowywać komentarze reprezentujące każdy token według własnego elementu AST, ale są dołączone do innego elementu AST oprócz zwykłego związku zawierającego. Dobrym pomysłem jest sprawdzenie wszystkich implementacji parsera / AST dla języków źródłowych dostępnych w otwartym środowisku IDE.
Jedną z bardzo dobrych implementacji jest infrastruktura kompilatora Eclipse dla języka Java. Zachowują komentarze podczas tokenizacji i reprezentują komentarze w AST - o ile pamiętam. Ponadto ta implementacja parsera / AST zachowuje formatowanie.
źródło