Помеченные комментарии
Напомню, что в одной из предыдущих статей отмечалась невозможность обеспечить вложенность длинных (скобочных) комментариев «/* ... */». Собственно говоря, нас заботила не вложенность как таковая, а возможность закомментировать любой код, не обращая внимания на его содержимое. А длинные комментарии «спотыкаются» о строки типа 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
Отзывы
✅ 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
|