Какой лучший способ обработки необязательных токенов в antlr4

Предположим, у меня есть следующие данные:

Great University
Graduated in 2010
Some University
09/2009 - 06/2011
Nice University
06/2011

Я хочу справиться с годами обучения. Моя грамматика выглядит так:

education:
    (section)*
    EOF
    ;

section:
    (school | years)+
   ;

degree:     WORD* DEGREE WORD* SEPARATOR;
years:      WORD* ( (YEAR_START '-')? YEAR_END) WORD* SEPARATOR;
WS          : [ \t\r]+ -> skip;
SEPARATOR   : (NEWLINE | COMMA);
COMMA       : ',';
NEWLINE     : '\n';
SCHOOL      : ('university' | 'University' | 'school' | 'School');
WORD        : [a-zA-Z'()]+;
YEAR_START  : YEAR;
YEAR_END    : YEAR;
YEAR        : (DIGIT DIGIT '/')? [1-2] DIGIT DIGIT DIGIT;
DIGIT       : [0-9];

Я получаю следующие ошибки:

line 1:17 mismatched input '\n' expecting '-'
line 6:17 mismatched input '\n' expecting '-'

Как я могу обработать необязательный начальный год с помощью грамматики?

1 ответ

Решение

Лексер может назначить только один тип токена одному шаблону. Вы ожидаете, что он назначит шаблон года трем типам токенов и во время выполнения решит, какой из них является правильным. Это не то, как работает ANTLR.

В вашем случае все годы (не только необязательные) будут учитываться по первому правилу, т.е. YEAR_START, Это означает, что после токенизации

"Graduated in 2010" -> WORD WORD YEAR_START

Единственное правило соответствия

 years:      WORD* ( (YEAR_START '-')? YEAR_END) WORD* SEPARATOR;

но "-" отсутствует.

Грамматика должна работать, если удалить YEAR_START а также YEAR_END правила и заменить все вхождения YEAR, Наверное YEAR_START а также YEAR_END имеют целью различать начало и конец, но для этого существуют метки.

Если это не работает, пожалуйста, опубликуйте свою полную грамматику, например ту, которую вы опубликовали, например, не содержит правила для DEGREE,

Другие вопросы по тегам