Как обычно анализируются комментарии?

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
@ Снеговик, есть такая перспектива, но, с другой стороны, если токен '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 */ */

это синтаксическая ошибка, так как комментарий открывается первым /*и закрывается первым*/

JacquesB
источник
3
В большинстве языков встроенные комментарии ( /* like this */) считаются равными одному пробелу, а завершенные EOL комментарии ( // like this) - пустой строке.
9000
@JacquesB, так что я думаю о том, чтобы рассматривать комментарии как полностью замененные из источника как пространство с нулевой шириной , что, по-видимому, эквивалентно тому, что вы предлагаете.
Сани
1
@artb обычное пространство должно работать просто отлично и находится в кодовой странице ASCII.
Джон Дворак
@JanDvorak пробел будет влиять на внешний вид и устраняет понимание, и он ближе к семантике «комментарий на самом деле не существует». Основным результатом рендеринга будет HTML, поэтому в моем случае ASCII не так важен, поскольку браузеры поддерживают Unicode. Тем не менее, я считаю, что стандарт C требует, чтобы комментарии заменялись одним пробелом.
Сани
1
Некоторые языки, особенно Racket, имеют вложенные многострочные комментарии: (define x #| this is #| a sub-comment |# the main comment |# 3) xвыходы 3.
wchargin
9

Чтобы ответить на вопрос:

Есть ли общее мнение о том, что обычно ожидается от повышения?

Я бы сказал, что никто не ожидает, что комментарий, встроенный в токен, будет законным.

Как правило, комментарии должны обрабатываться так же, как и пробелы. Любое место, которое могло бы иметь посторонние пробелы, также должно иметь встроенный комментарий. Единственным исключением будут строки:

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

Было бы странно поддерживать комментарии внутри строк, и было бы утомительно избегать их!

Коннор Кларк
источник
2
Никогда не думал о строках, это хороший крайний случай. Моя текущая мысль заключалась в том, чтобы сделать регулярное выражение между началом и концом комментария и заменить его одним пробелом. Это подорвало бы ваше дело.
Сани
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 приходит на ум, и у него очень простой ответ: без блочных комментариев. Вы начинаете комментарий с# а затем анализатор работает точно так, как если бы остальная часть строки не существовала, а была просто новой строкой.

В отличие от этого, Jade допускает комментарии блока , где блок заканчивается, когда вы возвращаетесь к тому же уровню отступа. Пример:

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

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

back2dos
источник
Хм, новая строка - это реальная проблема, так как мы используем синтаксис HTML \ XML для комментариев, поэтому он будет многострочным.
Сани
3
@ArtB Если вы используете синтаксис HTML / XML, было бы разумно просто использовать их поведение.
8bittree
1
@ 8bittree имеет смысл, должен был подумать об этом. Я оставлю вопрос как есть, так как он будет более полезным.
Сани
3

В прошлом я превращал комментарии в один токен как часть лексического анализа. То же самое касается строк. Оттуда жизнь проста.

В конкретном случае последнего созданного мной анализатора правило escape передается в процедуру синтаксического анализа верхнего уровня. Правило escape используется для обработки токенов, таких как комментарии, встроенные в основную грамматику. В общем, эти токены были отброшены.

Следствием этого является то, что в примере, который вы разместили с комментарием в середине идентификатора, идентификатор не будет единичным идентификатором - это ожидаемое поведение во всех языках (из памяти), с которыми я работал ,

Случай комментария внутри строки должен быть неявно обработан лексическим анализом. Правила для обработки строки не интересуют комментарии, и поэтому комментарий рассматривается как содержимое строки. То же самое относится к строке (или литералу в кавычках) внутри комментария - строка является частью комментария, который явно является единственным токеном; правила обработки комментария не интересуют строки.

Я надеюсь, что это имеет смысл / помогает.

user202190
источник
Итак, если у вас есть такой код console.log(/*a comment containing "quotes" is possible*/ "and a string containing /*slash-star, star-slash*/ is possible"), где в строке есть кавычки, а в строке - синтаксис комментария, как лексер узнает, как правильно его токенизировать? Можете ли вы отредактировать свой ответ, предоставив общее описание этих случаев?
Чарви
1

Это зависит от цели вашего парсера. Если вы напишите синтаксический анализатор для построения дерева разбора для компиляции, тогда комментарий не будет иметь семантического значения, кроме потенциально разделяющих токенов (например, метод / комментарий / (/ комментарий /)). В этом случае его рассматривают как пробелы.

Если ваш синтаксический анализатор является частью транспилятора, переводящего один исходный язык на другой исходный язык, или если ваш анализатор является препроцессором, который берет модуль компиляции на исходном языке, анализирует его, изменяет его и записывает измененную версию на том же исходном языке, комментарии как и все остальное становится очень важным.

Также, если у вас есть метаинформация в комментариях и вы особенно заботитесь о комментариях, например, при создании API-документации, как это делает JavaDoc, комментарии внезапно становятся очень важными.

Здесь комментарии часто прикрепляются к самим токенам. Если вы находите комментарий, вы присоединяете его к комментарию токена. Поскольку токен может иметь несколько токенов до и после, он снова зависит от того, как обрабатывать эти комментарии.

Идея аннотировать токены без комментариев с комментариями состоит в том, чтобы полностью удалить комментарии из грамматики.

Как только у вас есть дерево разбора, некоторые AST начинают распаковывать комментарии, представляющие каждый токен своим собственным AST-элементом, но присоединяемые к другому AST-элементу, помимо обычных вмещений. Хорошей идеей является проверка всех реализаций синтаксического анализатора / AST на наличие исходных языков, доступных в IDE с открытым исходным кодом.

Одна очень хорошая реализация - инфраструктура компилятора Eclipse для языка Java. Они сохраняют комментарии во время токенизации и представляют комментарии в AST - насколько я помню. Кроме того, эта реализация синтаксического анализатора / AST сохраняет форматирование.

Мартин Керстен
источник