Antlr4: правило одинарных кавычек не выполняется, если есть escape-символы плюс возврат каретки, новая строка - PullRequest
0 голосов
/ 25 ноября 2018

У меня есть грамматика как таковая:

grammar Testquote;
program : (Line ';')+ ;
Line: L_S_STRING ;
L_S_STRING  : '\'' (('\'' '\'') | ('\\' '\'') | ~('\''))* '\''; // Single quoted string literal
L_WS        : L_BLANK+ -> skip ;   // Whitespace
fragment L_BLANK : (' ' | '\t' | '\r' | '\n') ;

Эта грамматика - и L_S_STRING в частности - кажется, работает нормально с ванильными входами, такими как:

'ab';
'cd';

Однако, он не работает с этим вводом:

'yyyy-MM-dd\\'T\\'HH:mm:ss\\'Z\\'';
'cd';

И все же работает, когда я изменил первую строку на 'yyyy-MM-dd\\'T\\'HH:mm:ss\\'Z'''; или 'yyyy-MM-dd\\'T\\'HH:mm:ss\\'Z\\' ';

Я могу видеть, почему парсер может выбрать этонеудачный маршрут.Но есть ли какой-то способ, которым я могу сказать, чтобы он выбирал по-другому?

1 Ответ

0 голосов
/ 25 ноября 2018

Согласно документам ANTLR4 правила лексера и синтаксического анализатора жадные , что соответствует максимально возможному вводу .В вашем случае:

'yyyy-MM-dd\\'T\\'HH:mm:ss\\'Z\\'';
                               ^^^
'cd';

Ваша грамматика несколько двусмысленна - символы, которые я выделил, могут интерпретироваться как \' ' или как \ ''.Посмотрите, как это работает.

Без 'cd' лексер соответствует строке, потому что это допустимая строка для вашей грамматики, выделенные символы соответствуют \' '.Но поскольку лексер является жадным, он будет использовать вышеупомянутую неоднозначность для сопоставления нежелательных входных данных при первой возможности, например, при добавлении еще одного неэкранированного ' где-то позже.

Эта неоднозначность вызвана тем, что обратный слеш является либо нормальным символом, либопобег персонажа.Распространенным решением для устранения такой неоднозначности является правило для экранирования самого обратного слеша : \\, также вам необходимо не соответствовать ему как обычному символу .

В качестве альтернативы, вы можете решить проблему неоднозначности по-другому.Если вы хотите расставить приоритеты \' над '', вы должны написать:

L_S_STRING  : '\'' ( ('\'\'') | ('\\'+ ~'\\') | ~('\'' | '\\') )* '\'' ;

Это будет работать для вашего ввода.

Кстати, вы можете сократить свой код для L_WS:

L_WS : [ \t\n\r]+ -> skip ;
...