Обрабатывать новые строки явно только в части грамматики ANTLR - PullRequest
3 голосов
/ 20 июня 2020

В настоящее время я разрабатываю синтаксический анализатор для старого проприетарного языка разметки, который должен быть преобразован в новый стандарт. Для этого я использую ANTLR 4.

Структура состоит из блоков, разделенных определенным c стартером и его относительным ограничителем (например, { ... }, <. .. >, INPUT ... END). Внутри каждого блока элементы указываются в строках, разделенных символами новой строки; на самом деле, только где-то эти новые строки нужны, чтобы понять, что означает код.

Например:

< ID
SOME_VAR "optional modifier string"
$anEnvironmentVariable
"a constant string"
"another constant" "with its optional modifier"
>

Правило парсера, подобное следующему

field
  : OPEN_ANGLED_BRACKET row_id
    ((ENVIRONMENT_VAR | DQUOTE_STR | VAR) DQUOTE_STR?)+
    CLOSED_ANGLED_BRACKET
  ;

// [...]

WHITESPACE
  : [ \t\r\n] -> skip
  ;

, может легко проанализировать приведенный выше пример, но поскольку новые строки игнорируются, он не может различить guish, если строка в двойных кавычках является константой (что означает, что она находится в начале строки) или строкой модификатора (которая следует за предыдущей переменная / константа в той же строке).

Фактически я мог бы явно обработать новую строку следующим образом:

field
  : OPEN_ANGLED_BRACKET row_id NEWLINE
    ((ENVIRONMENT_VAR | DQUOTE_STR | VAR) DQUOTE_STR? NEWLINE)+
    CLOSED_ANGLED_BRACKET NEWLINE
  ;

// [...]

WHITESPACE
  : [ \t] -> skip
  ;

NEWLINE
  : '\r'? '\n'
  | '\r'
  ;

, но тогда я должен явно обрабатывать новую строку везде в остальной части грамматики , что сильно усложняет!

Есть ли способ сохранить явную новую строку внутри угловых скобок, пропуская ее везде «автоматически»?

Ответы [ 2 ]

2 голосов
/ 20 июня 2020

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

Дерево синтаксического анализа:

введите описание изображения здесь

2 голосов
/ 20 июня 2020

Здесь вы можете использовать лексические режимы . Для использования лексических режимов вам придется определить отдельные грамматики лексического анализатора и лексического анализатора.

Всякий раз, когда вы встречаете ENVIRONMENT_VAR, VAR или DQUOTE_STR в лексере (первое значение в строке), вы меняете лексический режим. В этом новом лексическом режиме вы сопоставляете 3 вещи: строки, пробелы (которые вы пропускаете) и новые строки (которые вы также пропускаете, и после этого токена вы возвращаетесь в режим по умолчанию). Все это может показаться немного расплывчатым, поэтому вот короткая демонстрация всего этого:

File: MarkupLexer.g4

lexer grammar MarkupLexer;

ENVIRONMENT_VAR       : '$' VAR    -> mode(MODIFIER_MODE);
VAR                   : [a-zA-Z_]+ -> mode(MODIFIER_MODE);
DQUOTE_STR            : STR        -> mode(MODIFIER_MODE);
OPEN_ANGLED_BRACKET   : '<';
CLOSED_ANGLED_BRACKET : '>';
SPACES                : [ \t\r\n] -> skip;

fragment STR : '"' ~["\r\n]* '"';

mode MODIFIER_MODE;

  MODIFIER_MODE_SPACES : [ \t] -> skip;
  MODIFIER_MODE_NL     : [\r\n]+ -> skip, mode(DEFAULT_MODE);
  MODIFIER_MODE_STRING : STR;

Парсер будет выглядеть так:

Файл: MarkupParser.g4

parser grammar MarkupParser;

options {
  tokenVocab=MarkupLexer;
}

field
  : OPEN_ANGLED_BRACKET row_id row+ CLOSED_ANGLED_BRACKET
  ;

row
 : (ENVIRONMENT_VAR | DQUOTE_STR | VAR) MODIFIER_MODE_STRING?
 ;

row_id
 : VAR
 ;

При синтаксическом анализе ввода:

< ID
SOME_VAR "optional modifier string"
$anEnvironmentVariable
"a constant string"
"another constant" "with its optional modifier"
>

вы получите следующее дерево синтаксического анализа:

enter image description here

...