Як зазвичай аналізуються коментарі?


31

Як в основному трактуються коментарі в мовах програмування та розмітці? Я пишу парсер для якоїсь спеціальної мови розмітки і хочу слідувати принципу найменшого здивування , тому намагаюся визначити загальну умову.

Наприклад, чи повинен коментар, вбудований в маркер, «втручається» у маркер чи ні? Як правило, це щось на кшталт:

Sys/* comment */tem.out.println()

чинне?

Крім того, якщо мова чутлива до нових рядків, а коментар охоплює новий рядок, слід вважати новий рядок чи ні?

stuff stuff /* this is comment
this is still comment */more stuff 

поводиться як

stuff stuff more stuff

або

stuff stuff
more stuff

?

Я знаю, що робить кілька конкретних мов, і я не шукаю думок, але шукаю: чи існує загальний консенсус, що, як правило, очікується від націнки на маркери та нові рядки?


Мій конкретний контекст - це розмітка, схожа на вікі.


Чи існує новий рядок всередині коментаря? Чому до цього коментаря траплялося б інакше, ніж будь-який інший персонаж?

1
@Snowman є така перспектива, але, з іншого боку, якщо маркер 'x' має особливе значення, якщо це перший маркер у рядку, і він здається першим жетоном на лінії як для людини, яка дивиться на джерело, так і на читання синтаксичного аналізатора Схоже на дилему, тому я задав питання.
Санки

4
Мені потрібно було це зробити саме до специфікації деякий час тому, і я визнав , що документи Gcc є відмінним ресурсом. Є деякі дивні кутові випадки, які ви, можливо, не розглядали.
Карл Білефельдт

Відповіді:


40

Зазвичай коментарі скануються (і відкидаються) як частина процесу токенізації, але до їхнього розбору. Коментар працює як роздільник токенів навіть за відсутності пробілів навколо нього.

Як ви зазначаєте, специфікація C чітко зазначає, що коментарі замінюються єдиним пробілом. Це лише специфікація-лінго, оскільки аналізатор реального світу насправді нічого не замінить, а просто сканує та відкидає коментар так само, як він сканує та відкидає символи пробілу. Але це пояснює просто, що коментар розділяє маркери так само, як і пробіл.

Вміст коментарів ігнорується, тому рядки у багаторядкових коментарях не впливають. Мови, чутливі до розривів рядків (Python та Visual Basic), зазвичай не мають багаторядкових коментарів, але JavaScript є одним винятком. Наприклад:

return /*
       */ 17

Еквівалентно

return 17

ні

return
17

Однорядкові коментарі зберігають розрив рядка, тобто

return // single line comment
    17

еквівалентно

return
17

ні

return 17

Оскільки коментарі скануються, але не аналізуються, вони, як правило, не гніздяться. Так

 /*  /* nested comment */ */

є синтаксичною помилкою, оскільки коментар відкривається першим, /*а закривається першим*/


3
У більшості мов лінійні коментарі ( /* like this */) вважаються рівними одній пробілі, а коментарі, що закінчуються EOL ( // like this), порожнім рядком.
9000

@JacquesB, тому я думаю розглянути коментарі як замінені в повному обсязі від джерела як простір нульової ширини , що здається еквівалентним тому, що ви пропонуєте.
Sled

1
@artb звичайний простір повинен працювати чудово і лежить на кодовій сторінці ASCII.
Джон Дворак

@JanDvorak пробіл буде впливати на зовнішній вигляд і знімає розуміння і ближче до семантики "коментаря насправді немає". Основним результатом візуалізації буде HTML, тому в моєму випадку ASCII не є проблемою, оскільки браузери підтримують Unicode. Зважаючи на це, я вважаю, що стандарт С мандатів коментарів замінюється єдиним пробілом.
Sled

1
Деякі мови, зокрема Ракетка, мають вкладені багаторядкові коментарі: (define x #| this is #| a sub-comment |# the main comment |# 3) xурожай 3.
wchargin

9

Щоб відповісти на запитання:

чи існує загальний консенсус, що, як правило, очікується від націнки?

Я б сказав, що ніхто не очікує, що коментар, вбудований у токен, буде законним.

Як правило, коментарі слід розглядати так само, як пробіли. Будь-яке місце, на якому було б дійсно мати сторонні пробіли, також повинно мати вкладений коментар. Єдиним винятком будуть рядки:

trace("Hello /*world*/") // should print Hello /*world*/

Було б досить дивно підтримувати коментарі всередині рядків, і це зробило б уникнення їх нудним!


2
Ніколи не замислювався про струни, це хороший крайній випадок. Моя нинішня думка робила просте зворотнє вираження між початком і закінченням коментарів і замінюючи його єдиним пробілом. Це призвело б до спрацьовування вашої справи.
Sled

3
Позначте +1 за цей біт про втечу струн. Хоча, у вашому прикладі, я б, як правило, очікував, що він надрукує, Hello /* world*/!а не придушує обмежувачі коментарів. Також ласкаво просимо до програмістів!
8bittree

1
Дякую 8bittree! І це абсолютно те, що я мав на увазі. Як не дивно, мені також потрібно уникнути ** у своїй відповіді ....
Коннор Кларк

2
@ArtB взагалі, "розбір за допомогою підстановки" стає дуже хитромудре в дорозі з крайніми справами та взаємодією з іншими функціями, і його краще уникати спочатку.
варення

7

У нечутливих до пробілів мовах ігноровані символи (тобто пробіли або ті, що є частиною коментаря) обмежують лексеми.

Так, наприклад, Sys temє два жетони, а Systemодин. Корисність цього може бути більш очевидною, якщо порівнювати, new Foo()і newFoo()один з яких побудує екземпляр, Fooа інший викликає newFoo.

Коментарі можуть грати ту саму роль, що і пробіг пробілів, наприклад, new/**/Foo()працює так само, як і new Foo(). Звичайно, це може бути складнішим, наприклад, new /**/ /**/ Foo()чи ні.

Технічно слід допускати коментарі в межах ідентифікаторів, але я сумніваюся, що це особливо практично.

Тепер, що стосується чутливих до простору мов?

Python приходить в голову, і він має дуже просту відповідь: немає блокових коментарів. Ви починаєте коментар, #а потім аналізатор працює точно так, як ніби решта рядка не існувала, а була лише новим рядком.

На відміну від цього, нефрит дозволяє коментувати блоки , коли блок закінчується, коли ви повернетесь до того ж рівня відступу. Приклад:

body
  //-
    As much text as you want
    can go here.
  p this is no longer part of the comment

Тож у цій царині я б не сказав, що ти можеш сказати, як справи вдається зазвичай . Спільним є те, що коментар завжди закінчується кінцевим рядком, а це означає, що всі коментарі діють точно так само, як нові рядки.


Хм, новий рядок - справжня проблема, оскільки ми використовуємо синтаксис HTML \ XML для коментарів, тому він буде багаторядковим.
Санки

3
@ArtB Якщо ви використовуєте синтаксис HTML / XML, можливо, було б просто використовувати їх поведінку.
8bittree

1
@ 8bittree має сенс, варто було б подумати про це. Я залишлю питання так, як це буде кориснішим у такий спосіб.
Санки

3

У минулому я перетворював коментарі в одну лексему як частину лексичного аналізу. Те саме стосується струн. Звідти життя легке.

У конкретному випадку останнього створеного я аналізатора правило втечі передається до процедури розбору верхнього рівня. Правило втечі використовується для обробки лексем, таких як маркери коментарів, вбудовані в основну граматику. Загалом, ці жетони були відкинуті.

Наслідком цього є те, що у прикладі, який ви розмістили з коментарем посеред ідентифікатора, ідентифікатор не був би єдиним ідентифікатором - це очікувана поведінка на всіх мовах (з пам'яті), з якими я працював .

Випадок коментаря в рядку повинен неявно оброблятися лексичним аналізом. Правила поводження з рядком не мають інтересу до коментарів, і як такий коментар трактується як вміст рядка. Це ж стосується рядка (або цитованого буквального) в коментарі - рядок є частиною коментаря, яка явно є єдиним маркером; правила обробки коментаря не представляють інтересу до рядків.

Я сподіваюся, що це має сенс / допомагає.


Отже, якщо у вас є такий код, як console.log(/*a comment containing "quotes" is possible*/ "and a string containing /*slash-star, star-slash*/ is possible"), де в рядку синтаксис коментарів і коментарів є рядок, як би лексер знав, щоб правильно його цекенізувати? Чи можете ви редагувати свою відповідь, надаючи загальний опис цих випадків?
chharvey

1

Це залежить від того, яку мету має ваш парсер. Якщо ви пишете аналізатор для побудови дерева розбору для компіляції, то коментар не має семантичного значення поряд з потенційно відокремлюваними лексемами (наприклад, метод / коментар / (/ коментар /)). У цьому випадку до неї звертаються як пробіли.

Якщо ваш аналізатор є частиною транспілера, що перекладає одну мову джерела на іншу мову джерела, або якщо ваш аналізатор є препроцесором, який приймає одиницю компіляції мовою джерела, аналізує її, модифікує її і записує модифіковану версію назад тією ж мовою джерела, коментарі як і все інше стає дуже важливим.

Крім того, якщо ви маєте мета-інформацію в коментарях, і ви особливо дбаєте про коментарі, наприклад, при створенні API-документації, як це робить JavaDoc, коментарі раптом дуже важливі.

Тут коментарі часто додаються до самих жетонів. Якщо ви знайдете коментар, додайте його до коментаря лексеми. Оскільки маркер може мати декілька маркерів до і після, це знову-таки залежить від способу обробки цих коментарів.

Ідея коментувати лексеми без коментарів із коментарями - це взагалі видалити коментарі з граматики.

Після того, як у вас є дерево розбору, деякі AST починають розпаковувати коментарі, що представляють кожен маркер власного AST-елемента, але приєднуються до іншого AST-елемента поруч із звичайними зв'язками містять. Доброю ідеєю є перевірка всіх реалізацій парсера / AST для мов джерела, наявних у IDE з відкритим кодом.

Одним з дуже хороших варіантів є інфраструктура компілятора Eclipse для мови Java. Вони зберігають коментарі під час токенізації та представляють коментарі в рамках AST - наскільки я пам’ятаю. Також ця аналізатор / реалізація AST зберігає форматування.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.