Лексер - очень простой объект: без вмешательства анализатора он маркирует входной источник. Итак, вход:
pid = something.pid
is not , маркированный как:
PID EQ WORD POINT WORD
а как:
PID EQ WORD POINT PID
Вот почему ваше правило:
pid
: PID EQ (WORD|POINT)+
;
соответствует "pid = something."
и оставляет второй "pid"
в потоке токенов, ожидая, что EQ
примет его (отсюда исключение).
Возможное исправление - сделать что-то вроде этого:
pid
: PID EQ (word|POINT)+
;
log
: LOG EQ (word|POINT)+
;
word
: WORD
| PID
| LOG
;
Или, сделав что-то вроде:
pid
: PID EQ FULL_WORD
;
log
: LOG EQ FULL_WORD
;
// ...
FULL_WORD
: WORD (POINT WORD)*
;
// ...