Можно ли описать комментарии блока с помощью EBNF?

Скажем, у меня есть следующий EBNF:

document    = content , { content } ;
content     = hello world | answer | space ;
hello world = "hello" , space , "world" ;
answer      = "42" ;
space       = " " ;

Это позволяет мне разобрать что-то вроде:

hello world 42

Теперь я хочу расширить эту грамматику блочным комментарием. Как я могу сделать это правильно?

Если я начну с простого:

document    = content , { content } ;
content     = hello world | answer | space | comment;
hello world = "hello" , space , "world" ;
answer      = "42" ;
space       = " " ;
comment     = "/*" , ?any character? , "*/" ;

не могу разобрать:

Hello /* I'm the taxman! */ World 42

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

document    = content , { content } ;
content     = hello world | answer | space | comment;
hello world = "hello" , { comment } , space , { comment } , "world" ;
answer      = "42" ;
space       = " " ;
comment     = "/*" , ?any character? , "*/" ;

Но я все еще не могу разобрать что-то вроде:

Hel/*p! I need somebody. Help! Not just anybody... */lo World 42

Как бы я сделал это с грамматикой EBNF? Или это вообще невозможно?


person jan.sende    schedule 27.08.2019    source источник
comment
Какой инструмент вы используете для проверки своей грамматики?   -  person whydoubt    schedule 28.08.2019
comment
@whydoubt ничего, кроме моей головы.   -  person jan.sende    schedule 28.08.2019


Ответы (2)


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

hello_world = "h", {comment}, "e", {comment}, "l", {comment}, "l", {comment}, "o" ,
              { comment }, space, { comment },
              "w", {comment}, "o", {comment}, "r", {comment}, "l", {comment}, "d" ;

Принимая во внимание более широкий вопрос, кажется общепринятым не описывать языковые комментарии как часть формальной грамматики, а вместо этого делать их в качестве примечания. Однако обычно это можно сделать, рассматривая комментарий как эквивалент пробела:

space = " " | comment ;

Вы также можете рассмотреть возможность добавления правила для описания последовательных пробелов:

spaces = { space }- ;

Очистка вашей окончательной грамматики, но обращение с «hello» и «world» как с токенами (т. е. с запретом их разбиения на части) может привести к чему-то вроде этого:

document    = { content }- ;
content     = hello world | answer | space ;
hello world = "hello" , spaces , "world" ;
answer      = "42" ;
spaces      = { space }- ;
space       = " " | comment ;
comment     = "/*" , ?any character? , "*/" ;
person whydoubt    schedule 28.08.2019
comment
В ISO 14977 подчеркивание является другим символом (7.5) и не должно использоваться в мета-идентификаторе. См. мое объяснение в разделе пробелы EBNF в метаидентификаторах. - person Rick Smith; 28.08.2019
comment
В ISO 14977 повторение может обозначаться пустым кроме, поэтому один или несколько пробелов могут отображаться как spaces = { }-;. См. мое объяснение в разделе Как обозначить хотя бы одно повторение в EBNF?. - person Rick Smith; 28.08.2019
comment
@RickSmith Я видел, как подчеркивание использовалось в другом месте, и не понимал, что его не следует использовать, поэтому я отредактирую соответствующим образом. В то время как это обозначение для одного или нескольких кажется странным, и оно также будет отредактировано. - person whydoubt; 28.08.2019
comment
Существует несколько вариантов имени EBNF, но OP использовал пробел в мета-идентификаторе, характерный для ISO 14977. Рассматривали ли вы препроцессор для своего ответа? Это удалит комментарии, оставив оставшийся текст нетронутым. Кажется, это обеспечит более чистое решение. - person Rick Smith; 28.08.2019
comment
@RickSmith Аааа! Я просто использовал синтаксис Википедии, который, похоже, соответствует стандарту ISO 14977. :D - person jan.sende; 30.08.2019
comment
@whydoubt Спасибо за объяснение! Я действительно думал о вашем первом подходе, но нашел его слишком раздражающим, чтобы писать. Однако второй подход, похоже, работает для меня. Кстати. Есть ли какая-либо польза в том, чтобы не позволять комментариям разделять терминалы, кроме того, чтобы не попасть в ад за написание letter , { comment } , ... EBNF? - person jan.sende; 30.08.2019

Как бы я сделал это с грамматикой EBNF? Или это вообще невозможно?

Некоторые языки удаляют комментарии, некоторые заменяют их пробелом в препроцессоре. Удаление комментариев кажется самым простым решением этой проблемы. Однако это решение удалит комментарии из литералов, что обычно не делается.

document = preprocess, process;

preprocess = {(? any character ? - comment, ? append char to text ?)},
    ? text for input to process ?;

comment = "/*", {? any character ? - "*/"}, "*/", ? discard ?;

process = {content}-;

content = hello world | answer | spaces;

hello world = ("H" | "h"), "ello", spaces, ("W" | "w") , "orld";

answer = "42";

spaces = {" "}-;

Препроцессор, учитывая,

Hello /* I'm the taxman! */ World 42

производит

Hello  World 42

Обратите внимание на два пробела.

И для

Hel/*p! I need somebody. Help! Not just anybody... */lo World 42

производит

Hello World 42
person Rick Smith    schedule 29.08.2019
comment
Большинство языков заменяют комментарии символом пробела (по крайней мере, теоретически), поэтому Hel/* ... */lo — это две лексемы, а не одна. - person rici; 29.08.2019
comment
@rici А, теория против практики. Все(?) языки определяют комментарии и место их размещения. EBNF (6.7) определяет комментарии таким образом, что комментарии могут быть удалены (или заменены пробелом) не затрагивая язык, определенный синтаксисом. Другие языки, с которыми я знаком, используют комментарии конец строки, и удаление или замена пробелом не имеет значения. Однако в случае с LaTex удаление требуется, поскольку любое замещающее пространство станет частью документа. - person Rick Smith; 29.08.2019
comment
EBNF не позволяет размещать комментарии в середине синтаксического элемента, поэтому вы не можете вставить токен вокруг комментария. Это то же самое, что и синтаксис блочного комментария (/*...*/), который используется в C, C++, C#, CSS, D, EcmaScript (и вариациях), Java, PHP и, возможно, во многих других, и похож на блочный комментарий, например, в Lua. и Хаскелл. Когда я сказал «теоретически», я имел в виду, что языковому процессору не нужно физически заменять комментарий одним символом пробела; он должен действовать так, как будто это произошло (и он может по-прежнему правильно считать номера строк в сообщениях об ошибках). - person rici; 29.08.2019
comment
@rici В случае неуместного комментария в EBNF это будет синтаксическая ошибка; поэтому удаление или замена не имеет значения. Вопросы были следующими: How would I do this with an EBNF grammar? Or is it not even possible at all? Я представил, как и считаю, что это можно сделать. Возможно, это не очень хороший способ — уж точно не единственный — но это способ (перефразируя Ницше). Я не возражаю против того, что вы сказали; это просто не относится к этому вопросу. Возможно, ОП спросит об этом позже. - person Rick Smith; 29.08.2019
comment
Спасибо! Прошу прощения за то, что не указал это прямо в вопросе, но я хочу оставить свои комментарии в AST. Таким образом, хотя в других случаях он может хорошо работать, препроцессор — это не то, что мне нужно. Тем не менее, я даю вам голос за хороший ответ. - person jan.sende; 30.08.2019