Да, это из-за префикса '.'
-s.
Всякий раз, когда лексер натыкается на ".a"
, он пытается создать токен AND_T
. Если символы "nd"
не могут быть найдены, лексер пытается создать еще один токен, который начинается с ".a"
, которого нет (и ANTLR выдает ошибку). Таким образом, лексер не вернет символ "a"
и отступит, чтобы создать токен DOT_T
(а затем токен ID
)! Так работает ANTLR.
Что вы можете сделать, это при желании сопоставить эти AND_T
, EQ_T
, ... внутри правила DOT_T
. Но все же вам нужно будет немного «помочь» лексеру, добавив некоторые синтаксические предикаты, которые заставляют лексера смотреть в поток символов, чтобы убедиться, что он может соответствовать этим токенам.
Демонстрация:
grammar T;
parse
: (t=. {System.out.printf("\%-10s '\%s'\n", tokenNames[$t.type], $t.text);})* EOF
;
DOT_T
: '.' ( (AND_T)=> AND_T {$type=AND_T;}
| (EQ_T)=> EQ_T {$type=EQ_T; }
| (NE_T)=> NE_T {$type=NE_T; }
)?
;
ID
: ('a'..'z' | 'A'..'Z')+
;
LPAREN_T
: '('
;
RPAREN_T
: ')'
;
SPACE
: (' ' | '\t' | '\r' | '\n')+ {skip();}
;
NUMBER_T
: DIGIT+ ((DECIMAL)=> DECIMAL)?
;
fragment DECIMAL : '.' DIGIT+ ;
fragment AND_T : ('AND' | 'and') '.' ;
fragment EQ_T : ('EQ' | 'eq' ) '.' ;
fragment NE_T : ('NE' | 'ne' ) '.' ;
fragment DIGIT : '0'..'9';
А если вы передаете сгенерированный парсер, то ввод:
a.eq.b.and.c.ne.d
c.append(b)
будет напечатан следующий вывод:
ID 'a'
EQ_T '.eq.'
ID 'b'
AND_T '.and.'
ID 'c'
NE_T '.ne.'
ID 'd'
ID 'c'
DOT_T '.'
ID 'append'
LPAREN_T '('
ID 'b'
RPAREN_T ')'
А для ввода:
lda.eq.3.and.dim.eq.3
печатается следующее:
ID 'lda'
EQ_T '.eq.'
NUMBER_T '3'
AND_T '.and.'
ID 'dim'
EQ_T '.eq.'
NUMBER_T '3'
EDIT
Тот факт, что DECIMAL
и KIND
оба начинаются с '.' DIGIT+
, не годится. Попробуйте что-то вроде этого:
NUMBER_T
: DIGIT+ ((DECIMAL)=> DECIMAL ((KIND)=> KIND)?)?
;
fragment DECIMAL : '.' DIGIT+;
fragment KIND : '_' (ALPHA+ | DIGIT+); // removed ('.' DIGIT+) from this fragment
Обратите внимание, что правило NUMBER_T
теперь никогда не будет выдавать токены DECIMAL
или KIND
. Если вы хотите, чтобы это произошло, вам нужно изменить тип:
NUMBER_T
: DIGIT+ ((DECIMAL)=> DECIMAL {/*change type*/} ((KIND)=> KIND {/*change type*/})?)?
;