Надлежащий способ разрешить неоднозначности правила лексера ANTLR? - PullRequest
6 голосов
/ 26 января 2012

Пожалуйста, смотрите исходный код по адресу: https://gist.github.com/1684022.

У меня определены два токена:

ID  :   ('a'..'z' | 'A'..'Z') ('0'..'9' | 'a'..'z' | 'A'..'Z' | ' ')*;

PITCH   
    :   (('A'|'a') '#'?)
    |   (('B'|'b') '#'?) 
    |   (('C'|'c') '#'?);

Очевидно, буква «А» была бы двусмысленностью.

Я также определяю:

note    :   PITCH;
name    :   ID;
main    :   name ':' note '\n'?

Теперь, если я введу «A: A» в качестве входных данных для парсера, я всегда получаю сообщение об ошибке. Либо синтаксический анализатор ожидает PITCH или ID в зависимости от того, определен ли сначала ID или PITCH:

mismatched input 'A' expecting ID

Как правильно решить эту проблему, чтобы она работала как задумано?


Как описано, хотя интуитивно понятно, как должен выполняться синтаксический анализ, ANTLR не делает "правильную вещь". То есть, хотя правило main гласит, что name / ID должно стоять первым, лексер, кажется, не знает об этом и идентифицирует «A» как PITCH, поскольку оно следует за «самым длинным соответствием» / Правило «которое приходит первым», а не более разумное правило, о котором говорит правило.

Является ли единственным решением подделать / взломать его, сопоставив ID и PITCH, а затем рекомбинировать их позже, как говорит dasblinkenlight?

1 Ответ

5 голосов
/ 26 января 2012

Вот как я переформулирую эту грамматику, чтобы она заработала:

ID  :   (('a'..'z' | 'A'..'Z') ('0'..'9' | 'a'..'z' | 'A'..'Z' | ' ')+)
    |   ('d'..'z' | 'D'..'Z');

PITCH : 'a'..'c' | 'A'..'C';

SHARP : '#';

note    :   PITCH SHARP?;

name    :   ID | PITCH;

main    :   name ':' note '\n'? EOF

Это отделяет длинные имена от односимвольных имен основного тона, которые "воссоединяются" в парсере. Также «острый» токен получает свое собственное имя и распознается в анализаторе как необязательный токен.

...