Разбор строк со встроенными многострочными управляющими символами - PullRequest
0 голосов
/ 29 июня 2019

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

'some text'\1B 1B 1B\'some more text'.

Последовательность управляющих символов имеет префикс «\» и заканчивается «\». Внутри последовательности управления находятся две цифры номера, которые определяют управляющий символ.

В приведенном выше примере результирующей строкой будет

'some textESCESCESCsome more text'

ESC обозначает непечатный escape-символ ASCII.

Кроме того, внутри последовательности контрольных символов новой строке разрешено создавать многострочные строки, например,

'some text'\1B 
1B 
1B\'some more text'.

, что приводит к той же строке, что и выше.

grammar stringliteral;

tokens {
    CHAR,CHARS,CTRLCHARS,ESC,WHITESPACE,NEWLINE
}

stringLiteral:  '\'' CHARS? '\'' ;

fragment
CHARS: CHAR+ ;

fragment
CHAR: CTRLCHARS | ~['\n\r] ;

fragment
ESC: '\'\\' ;

fragment
CTRLCHARS: ESC ~['] ESC;

WHITESPACE: (' ' | '\t')+ -> channel(HIDDEN);

NEWLINE: ( '\r' '\n'? | '\n' ) -> channel(HIDDEN);

Лексер / парсер выше ведет себя очень странно, потому что он принимает только строка в форме 'x' и игнорирует несколько символов и последовательность управляющих символов.

Возможно, я наблюдаю за чем-то очевидным. Любая подсказка или идея, как решить эту проблему, приветствуется!

Я исправил грамматику в соответствии с подсказками Майка:

grammar stringliteral;

tokens {
     STRING
}

stringLiteral: STRING;
STRING: '\'' ( '\'' '\\' | '\\' '\'' | . )*? '\'';

По-прежнему существует проблема с распознаванием конца последовательности контрольных символов:

Ввод 'A STRING' \ CTRL \ '' вызывает ошибки

Line 1:10 token recognition error at: '\'
line 1:11 token recognition error at: 'C'
line 1:12 token recognition error at: 'T'
line 1:13 token recognition error at: 'R'
line 1:14 token recognition error at: 'L'
line 1:15 token recognition error at: '\'

Есть идеи? Кстати: мы используем antlr v 4.5.

Ответы [ 2 ]

0 голосов
/ 01 июля 2019

Я решил проблему с этим фрагментом грамматики, адаптировав правила оценки из примера поздней грамматики Java:

StringLiteral
    :   '\'' StringCharacters? '\''
    ;

fragment
StringCharacters
    :   StringCharacter+
    ;

fragment
StringCharacter
    :   ~['\\\r\n]
    |   EscapeSequence
    ;

fragment
EscapeSequence
    : '\'\\' (HexEscape| ' ' | [\r\n])* '\\\''
    ;

fragment
HexEscape
    :  B4Digit B4Digit
    ;

fragment
B4Digit
    : '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 'A' | 'B' |     'C' | 'D' | 'E' | 'F'
    ;
0 голосов
/ 30 июня 2019

Есть несколько проблем с этой грамматикой:

  1. Нельзя использовать правило лексера фрагмента в правиле синтаксического анализатора.
  2. Ваше строковое правило является правилом синтаксического анализа, поэтому оно подлежит автоматическому удалению пробелов, которое вы определили с помощью правил WHITESPACE и NEWLINE.
  3. У вас нет правила принимать последовательность контрольных символов, например \1B 1B 1B.

Особенно третий пункт - реальная проблема, поскольку вы не знаете, где заканчивается ваша последовательность управления (если только это не была опечатка, и вы на самом деле имели в виду: \1B \1B \1B.

В любом случае, не работайте с escape-последовательностями в вашем лексере (за исключением минимальной обработки, необходимой для работы правила, то есть обработки последовательности \'. Вам нужно просто разобрать весь текст, и вы можете выяснить escape-последовательности в вашей семантической фазе:

STRING: '\' ('\\' '\'' | . )*? '\''; 

Примечание *? - это не жадный оператор, который останавливается на первой закрывающей кавычке. Без этого лексер продолжал бы сопоставлять все последующие (экранированные и не экранированные) кавычки в одном и том же строковом правиле (жадное поведение). Кроме того, строковое правило теперь является правилом лексера, на которое не влияет пропуск пропусков.

...