Проблемы с определением анализатора ANTLR для файла шаблона - PullRequest
1 голос
/ 18 июня 2020

Я начал работать с ANTLR4, чтобы создать синтаксический анализатор для самостоятельно определенного формата файла шаблона.

Формат в основном состоит из обязательной части, называемой «#settings», и по крайней мере одной части, называемой «#region». Тело частей окружено фигурными скобками.

Я создал образец файла, а также скопировал-вставил-модифицировал файл antlr g4 для его анализа. Пока работает нормально:

Файл:

#settings
{
setting1: value1
setting2: value2
}

#region
{
[Key1]=Value1(Comment1)
[Key2]=Value2(Comment2)
}

Файл G4 для этого примера:

grammar Template;

start
    : section EOF
    ;

section
    : settings regions
    ;

settings
    : '#settings' '{' (settingsText)* '}'
    ;

settingsText
    : TEXT
    ;

regions
    : (region)+
    ;

region
    : '#region' '{' (regionText)* '}'
    ;

regionName
    : NOSPACE
    ;

regionText
    : TEXT
    ;

TEXT
    : (~[\u0000-\u001F])+
    ;

NOSPACE
    : (~[\u0000-\u0020])+
    ;

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

Это работает, как ожидалось. Теперь я хочу усложнить формат файла и парсер и расширить заголовок #region на #region NAME (атрибуты). Итак, что я изменил в образце и в файле G4:

Образец изменен на

...
#region name (attributes, moreAttributes)
{
...

, а файл g4 изменен на

grammar Template;

start
    : section EOF
    ;

section
    : settings regions
    ;

settings
    : '#settings' '{' (settingsText)* '}'
    ;

settingsText
    : TEXT
    ;

regions
    : (region)+
    ;

region
    : '#region' regionName (regionAttributes)? '{' (regionText)* '}'
    ;

regionName
    : NOSPACE
    ;

regionAttributes
    : '(' regionAttribute (',' regionAttribute)* ')'
    ;

regionAttribute
    : NOSPACE
    ;

regionText
    : TEXT
    ;

TEXT
    : (~[\u0000-\u001F])+
    ;

NOSPACE
    : (~[\u0000-\u0020])+
    ;

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

Теперь синтаксический анализатор выводит появляется следующая ошибка: Ошибка парсера (7, 1): несоответствующий ввод '#region name (attributes, moreAttributes)' ожидает '# region'

И я не понимаю, почему это ведет себя вот так. Я ожидал, что парсер не объединит всю строку при сравнении. Что я делаю не так?

Спасибо.

Ответы [ 2 ]

0 голосов
/ 19 июня 2020

Барт,

большое спасибо за разъяснение мне этого. Ключевая фраза была , лексер будет соответствовать как можно большему количеству символов . Мне еще нужно привыкнуть к такому поведению. Я переработал свои правила лексера и парсера, и теперь, похоже, они работают для моего тестового примера.

Для полноты, это мой файл g4 сейчас:

grammar Template;

start
    : section EOF
    ;

section
    : settings regions
    ;

settings
    : '#settings' '{' (settingsText)* '}'
    ;

regions
    : (region)+
    ;

region
    : '#region' regionName (regionAttributes)? '{' (regionText)* '}'
    ;

regionName
    : TEXT
    ;

settingsText
    : TEXT
    ;

regionAttributes
    : '(' regionAttribute (',' regionAttribute)* ')'
    ;

regionAttribute
    : TEXT
    ;

regionText
    : regionLine '('? (regionComment?) ')'?
    ;

regionLine
    : TEXT
    ;

regionComment
    : TEXT
    ;

TEXT
    : ([A-z0-9:\-|= ])+
    ;

WS
   : [ \t\n\r] + -> skip
   ;
0 голосов
/ 18 июня 2020

Здесь есть пара проблем:

  1. все, что соответствует NOSPACE, также совпадает с TEXT
  2. TEXT слишком жадно

Проблема 1

Лексер ANTLR работает независимо от парсера, и лексер будет соответствовать как можно большему количеству символов.

Когда 2 (или более) правила лексического анализатора соответствуют одинаковому количеству символов, то «выигрывает» тот, который определен первым.

Итак, если ввод - Foo, а синтаксический анализатор -. пытаясь сопоставить токен NOSPACE, вам не повезло: поскольку оба TEXT и NOSPACE соответствуют тексту Foo, а TEXT определяется первым, лексер создаст токен TEXT. С этим ничего не поделаешь: так работает ANTLR.

Проблема 2

Как объяснялось в проблеме 1, лексер пытается сопоставить как можно больше символов. Из-за этого ваше правило TEXT слишком жадно. Это то, что ваш ввод токенизируется как:

'{'                  `{`
TEXT                 `setting1: value1`
TEXT                 `setting2: value2`
'}'                  `}`
TEXT                 `#region name (attributes, moreAttributes)`
'{'                  `{`
TEXT                 `[Key1]=Value1(Comment1)`
TEXT                 `[Key2]=Value2(Comment2)`
'}'                  `}`

Как видите, TEXT совпадает слишком много. И это то, что ошибка

Parser error (7, 1): mismatched input '#region name (attributes, moreAttributes)' ожидает '# region'

. сообщая вам: #region name (attributes, moreAttributes) - это единственный токен TEXT, где #region пытается найти соответствие парсеру.

Решение?

Удалите NOSPACE и сделайте TEXT токен менее жадный (или наоборот).

...