Правила лексера строк Antlr4 DM - PullRequest
0 голосов
/ 05 декабря 2018

Я пытаюсь представить строки языка BYOND DM в форме лексера (см. http://byond.com и http://byond.com/docs/ref). Вот правила для строк:

  • Строканачинаются и заканчиваются двойными кавычками, т. е. "hello world" оценивается как hello world
  • Обратная косая черта действует как escape-символ, который может экранировать конечную кавычку, т. е. "hello\"world" оценивается как hello"world
  • Новые строки в строке можно игнорировать, заканчивая строку обратной косой чертой, т. Е. "hello\ world" оценивается как helloworld
  • Если строка открывается / закрывается с последовательностью {" / "} соответственно,символы новой строки разрешены и введены в окончательную строку. Последовательность \\\n по-прежнему игнорируется
  • Строка может содержать встроенные выражения внутри фигурных скобок, которые отформатированы в результате. Обратные косые черты могут экранировать открывающую фигурную скобку, т.е. "hello [ "world" ] \["во время выполнения оценивается как hello world [. Любое выражение может быть заключено в фигурные скобки (вызовы, математика и т. д.)
  • Если начальная кавычка / фигурная скобка начинаются с escape-последовательности «@» и вставляютсяexpressions отключены для строки.т. е. @{"hello [worl\d"} и @"hello [worl\d" оцениваются как hello [worl\d

Я пытаюсь создать правила лексера ANTLR4 .g4 для токенизации этих строк.Я полагаю, что мне нужно 4 (или более) типа токенов:

  • Обычная строка.т.е. "hello world", @"hello world", @{"hello world"} или {"hello world"}
  • Строка начинается перед вложенным выражением.т.е. "hello [ или {"hello [
  • Конец строки после встроенного выражения.т.е. ] world" или ] world"}
  • Строка между двумя встроенными выражениями.то есть ] hello world [

Вот мои (неполные и неудачные) попытки:

LSTRING: '"' ('\\[' | ~[[\r\n])* '[';
RSTRING: ']' ('\\"' | ~["\r\n])* '"'; 
CSTRING: ']' ('\\[' | ~[[\r\n])* '['; 
FSTRING: '"' ('\\"' | ~["\r\n])* '"';

Если это не может быть решено в лексере, я могу написать правила парсера намои собственные с токенами @, {", "}, [, ], \\ и ".Но, думаю, я бы попробовал, потому что это было бы более производительно.

1 Ответ

0 голосов
/ 11 декабря 2018

Я решил это с помощью следующих лексеров. Постоянная ссылка

...
@lexer::members
{
ulong regularAccessLevel;
System.Collections.Generic.Stack<bool> multiString = new System.Collections.Generic.Stack<bool>();
}
...
VERBATIUM_STRING: '@"' (~["\r\n])* '"';
MULTILINE_VERBATIUM_STRING: '@{"' (~'"')* '"}';
MULTI_STRING_START: '{"' { multiString.Push(true); } -> pushMode(INTERPOLATION_STRING);
STRING_START: '"' { multiString.Push(false); } -> pushMode(INTERPOLATION_STRING);
...
LBRACE: '[' { ++regularAccessLevel; };
RBRACE: ']' { if(regularAccessLevel > 0) --regularAccessLevel; else if(multiString.Count > 0) { PopMode(); } };
...
mode INTERPOLATION_STRING;
CHAR_INSIDE: '\\\''
    | '\\"'
    | '\\['
    | '\\\\'
    | '\\0'
    | '\\a'
    | '\\b'
    | '\\f'
    | '\\n'
    | '\\r'
    | '\\t'
    | '\\v'
    ;

EMBED_START: '[' -> pushMode(DEFAULT_MODE);
MULTI_STRING_CLOSE: {multiString.Peek()}? '"}' { multiString.Pop(); PopMode(); };
STRING_CLOSE: {!multiString.Peek()}? '"' { multiString.Pop(); PopMode(); };
STRING_INSIDE: {!multiString.Peek()}? ~('[' | '\\' | '"' | '\r' | '\n')+;
MULTI_STRING_INSIDE: {multiString.Peek()}? ~('[' | '\\' | '"')+;

Определенные строки могут привести к тому, что он будет выдавать несколько токенов STRING_INSIDE / MULTI_STRING_INSIDE в последовательности, но это допустимо, так как анализатор все равно будет использовать все это.

Во многом это связано с чтением интерполированных строк C # в примерах antlr4 Постоянная ссылка

...