Каким должен быть язык программирования? Анализ и критика Описание языка Компилятор
Отечественные разработки Cтатьи на компьютерные темы Компьютерный юмор Новости и прочее

Помеченные комментарии

Напомню, что в одной из предыдущих статей отмечалась невозможность обеспечить вложенность длинных (скобочных) комментариев «/* ... */». Собственно говоря, нас заботила не вложенность как таковая, а возможность закомментировать любой код, не обращая внимания на его содержимое. А длинные комментарии «спотыкаются» о строки типа char x[] = "*/".

            Для решения этой проблемы были предложены комментарии нового вида: «нерабочий код». Однако такое решение, как теперь видится, является слишком дорогим для такой дешёвой проблемы. Этот способ предполагает разбор лексем и вводит новую их категорию: недействующие лексемы. Это чревато неоправданным усложнением компилятора.

            Есть мысль сделать другой вид комментариев — помеченные комментарии. Каждый комментарий такого вида содержит уникальную метку в своём начале и такую же метку в конце. Внутри таких комментариев могут содержатся любые другие комментарии: хоть такие же помеченные (но с другой меткой), хоть длинные, короткие.

            Со стилем мы уже определились, длинные комментарии будут иметь вид «(* ... *)». Предлагаемый вид комментариев тоже будет начинаться и заканчиваться скобками. Где и как располагать метку? Наверное, лучше всего так:

(:метка
. . .
метка:)
Метка — это ряд символов, которые соответствуют лексеме «идентификатор». Двоеточие отсылает нас традиционным меткам в языках, в которых есть «goto»:
label_01: // какой-то код
. . .
goto  label_01:;


Помеченные комментарии


Обоснование выбора.
  • Почему не «(*метка ... метка*)»? Потому что нет возможности отличить его от длинного комментария «(* ... *)».
  • Почему не «(метка* ... *метка)»? Потому метка — это идентификатор и «(идентификатор*» выглядит как левая часть умножения.
  • Почему не «(метка: ... :метка)»? Потому метка — это идентификатор и «(идентификатор:» выглядит как левая часть операции «:». Этот символ пока нами не задействован для какой-либо операции. Но не стоит это трогать — вдруг пригодится.
Есть ли у этой идеи подводные камни? Да, они могут иметь место, например:
(:метка777
  char  x = "метка777:)";
  метка777:)
В таком случае легко избежать коллизии:
(:метка333
  char  x = "метка777:)";
  метка333:)
Т.е. меняется метка комментария, но не код, оказавшийся внутри него. С длинным комментарием такой номер не пройдёт, придётся менять сам текст. Проблемный код:
(* char  x = "*/"; *)
Вариант решения проблемы — изменение кода внутри:
(* char  x = "\x2A\x2F"; *)
            И так, наверное наилучший способ обозначения помеченных комментариев — это смайлики улыбки (если кто-то ещё не обратил на получившиеся графические очертания). Но есть вполне резонный вопрос: а есть ли смысл закладывать в язык отдельную конструкцию для борьбы с одним-единственным случаем, когда конец комментария внутри текста?

Опубликовано: 2018.11.09, последняя правка: 2022.01.21    13:24

ОценитеОценки посетителей
   ██████████████████ 3 (42.8%)
   ▌ 0
   ▌ 0
   ████████████████████████ 4 (57.1%)

Отзывы

✅  2018/11/11 14:27, Александр Коновалов aka Маздайщик          #0 

Похожая проблема в языках программирования возникает со строками — изобразить строку, которая сама содержит кавычки. Традиционное решение — escape-символы вроде ". Но некоторые языки программирования предлагают более хитрые способы.

Например, в Python можно строку ограничивать тремя кавычками: """...""" — весь текст между ними (включая переводы строк) становится содержимым строки. Таким образом в Python иногда записывают многострочные комментарии. Запись строкового литерала в строке считается выражением, а значит, оператором. Никакого побочного эффекта, кроме потери времени на интерпретацию, это не даёт. Недостаток — нельзя внутри использовать три кавычки подряд, но с этим питонисты мирятся.

Интересен подход Rust (https://doc.rust-lang.org/reference/tokens.html#raw-string-literals) — строка, которая начинается с r#...#", должна заканчиваться на "#...#, причём число решёток в начале и конце должно совпадать. Т.е., строки могут иметь вид r"...", r#"..."#, r##"..."##. Соответственно, если строка содержит "#### (кавычка и четыре решётки), то её можно погрузить в r#####"..."##### — (пять решёток).

Языки Bash и Perl для многострочных строк предоставляют т.н. heredoc-синтаксис (https://ru.wikipedia.org/wiki/Heredoc-синтаксис) (не знаю, как его лучше переводить на русский):
somecommand <<ENDOFTEXT
...
...
ENDOFTEXT
Семантика следующая: запускается команда somecommand, на стандартный ввод которой падают строчки между строкой запуска команды и строкой ENDOFTEXT. Строку вместо ENDOFTEXT можно записать любую:
somecommand <<ABCD
...
...
ABCD
Пример в Perl (псевдокод):
sql_call("SELECT * FROM table WHERE тут длиннющая длиннющая строка
JOIN table2 ON key GROUP BY
и ещё много букв на SQL, я не знаю SQL пишу от балды
всякую чушь ODRER DESCENT", param1, param2);
С heredoc’ами:
sql_call(<<SQLEND, param1, param2)
SELECT * FROM table
WHERE тут длиннющая длиннющая строка
JOIN table2 ON key
GROUP BY и ещё много букв на SQL,
я не знаю SQL пишу от балды всякую чушь
ORDER DESCENT
SQLEND
К чему я всё это написал. К тому, что комментарии и строки родственны тем, что внутри них может быть произвольный текст, и проблему символов-разделителей внутри приходится как-то решать. Для строк некоторые решения известны, подход для комментариев — новый.

Вариант, предложенный Автором сайта, немного напоминает подход Rust’а для строк и heredoc’и, но применён к комментариям, что, несомненно, является новшеством.

✅  2018/11/15 09:37, kt          #1 

Древний подход к символу кавычки внутри строки в кавычках — удвоение кавычки. Например, текст строки I’m back, будет выглядеть так: ’I’’m back’
Логических сложностей при лексическом разборе не возникает — вторую кавычку подряд надо просто игнорировать. Строка даже может состоять из одних кавычек — просто все их надо удвоить. При этом самая первая кавычка — признак самой строки и поэтому в удвоении не учитывается. Ещё одна удобная мелкая доработка — знак «крышка» ^ этот символ внутри строки гасит старшие три разряда в следующем байте. При этом в строке удобно пишутся управляющие символы, которые все становятся печатными, например строка ’^G^M^J’ бибикнет и переведет строку. Ну а сама "крышка" записывается, естественно, как две "крышки" подряд ))

✅  2018/11/15 17:59, Автор сайта          #2 

Разница между строками и комментариями всё-таки есть. Строки заключаются между одинаковых символов:
"строка"
. Чтобы внутри поместить этот символ, его надо просто задвоить:
"строка с "" кавычкой"
. Или строку поместить внутри одинарных кавычек, как в PHP:
'строка с " кавычкой'
Комментарии же заключаются между разных символов (допустим, между «/*» и «*/»):
/* комментарий */
Как мы можем задвоить эти символы? Так
/* длинный */*/ комментарий */
или так
/* длинный *//* комментарий */
?

✅  2018/11/15 23:30, kt          #3 

Замечу, что в нашем трансляторе PL/1 эта проблема, увы, также не решена. Т.е. у нас есть «объемлющий» комментарий /*[ .... ]*/, который ищет квадратную скобку вплотную к знаку комментария и, таким образом, пропускает почти любой текст внутри, поскольку [] вообще не входят в алфавит PL/1 (кстати, теперь входят и поэтому скобки физических типов нельзя писать вплотную к границам комментария).
Но так можно закомментировать кусок программы с «обычными» /* */ только один раз ((

✅  2018/11/16 12:53, Автор сайта          #4 

Что тогда остаётся? Либо предупреждать, что внутри строк "*/" надо менять на "\x2A\x2F", либо вот такие помеченные комментарии. Но оба варианта не вписываются в стандарт PL/1.

✅  2021/03/27 12:43, Виталий Монастырский          #5 

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

Добавить свой отзыв

Написать автору можно на электронную почту
mail(аt)compiler.su

Авторизация

Регистрация

Выслать пароль

Карта сайта


Содержание

Каким должен быть язык программирования?

Анализ и критика

●  Устарел ли текст как форма представления программы

●  Русский язык и программирование

●  Многоязыковое программирование

Синтаксис языков программирования

Синтаксический сахар

●  Некоторые «вкусности» Алгол-68

●  «Двухмерный» синтаксис Python

●  Почему языки с синтаксисом Си популярнее языков с синтаксисом Паскаля?

●  Должна ли программа быть удобочитаемой?

●  Стиль языка программирования

●  Тексто-графическое представление программы

●●  Разделители

●●  Строки программы

●●  Слева направо или справа налево?

●  Комментарии

●●  Длинные комментарии

●●  Короткие комментарии

●●  Комментарии автоматической генерации документации

●●  Нерабочий код

●●  Помеченные комментарии

●  Нужны ли беззнаковые целые?

●  Шестнадцатиричные и двоичные константы

●  Условные операторы

●  Переключатель

●  Циклы

●●  Продолжение цикла и выход из него

●  Некошерный «goto»

●  Изменение приоритетов операций

●  Операции присвоения и проверки на равенство. Возможно ли одинаковое обозначение?

●  Так ли нужны операции «&&», «||» и «^^»?

●  Постфиксные инкремент и декремент

●  Почему в PHP для конкатенации строк используется «.»?

●  Указатели и ссылки в C++

●●  О неправомерном доступе к памяти через указатели

●  Обработка ошибок

●  Функциональное программирование

●●  Нечистые действия в чистых функциях

●●  О чистоте и нечистоте функций и языков

●●  Макросы — это чистые функции, исполняемые во время компиляции

●●  Хаскелл, детище британских учёных

●●  Измеряем замедление при вызове функций высших порядков

●●  C vs Haskell: сравнение скорости на простом примере

●●  Уникальность имён функций: за и против

●●  Каррирование: для чего и как

●●  О тестах, доказывающих отсутствие ошибок

●  Надёжные программы из ненадёжных компонентов

●●  О многократном резервировании функций

●  Использование памяти

●  Почему динамическое распределение памяти — это плохо

●  Как обеспечить возврат функциями объектов переменной длины?

●●  Типы переменного размера (dynamically sized types, DST) в языке Rust

●●  Массивы переменной длины в C/C++

●●  Размещение объектов в стеке, традиционный подход

●●  Размещение объектов переменной длины с использованием множества стеков

●●  Размещение объектов переменной длины с использованием двух стеков

●●  Реализация двухстековой модели размещения данных

●●  Двухстековая модель: тесты на скорость

●●  Изменение длины объекта в стеке во время исполнения

●●  Размещение объектов переменной длины с использованием одного стека

●  Можно ли забыть о «куче», если объекты переменной длины хранить в стеке

●  Безопасность и размещение объектов переменной длины в стеке

●  Массивы, структуры, типы, классы переменной длины

●  О хранении данных в стеке, вместо заключения

●  Реализация параметрического полиморфизма

Описание языка

Компилятор

Отечественные разработки

Cтатьи на компьютерные темы

Компьютерный юмор

Новости и прочее




Последние отзывы

2024/10/15 22:49 ••• Неслучайный читатель
Русский язык и программирование

2024/10/14 18:05 ••• MihalNik
Энтузиасты-разработчики компиляторов и их проекты

2024/10/01 09:36 ••• Иван
О русском ассемблере

2024/09/30 00:08 ••• Автор сайта
Новости и прочее

2024/09/29 23:40 ••• Автор сайта
Десятка худших фич C#

2024/09/29 13:10 ••• Автор сайта
ЕС ЭВМ — это измена, трусость и обман?

2024/09/22 21:08 ••• Вежливый Лис
Бесплатный софт в мышеловке

2024/09/05 17:44 ••• Автор сайта
Правила языка: алфавит

2024/09/04 00:00 ••• alextretyak
Циклы

2024/09/02 22:24 ••• Автор сайта
Постфиксные инкремент и декремент

2024/08/26 00:37 ••• Автор сайта
Что нового с 1966 года?

2024/07/26 13:32 ••• Бурановский дедушка
Программирование исчезнет. Будет дрессировка нейронных сетей

2024/06/21 00:20 ••• Gudleifr
О превращении кибернетики в шаманство