Когда вы получаете сообщение об ошибке «Неожиданный ввод 'foo', ожидаемый BAR" и думаете, что "Но 'foo" - это бар "", первое, что вы должны сделать, это напечатать поток токеновдля вашего ввода (вы можете сделать это, запустив grun Symbols tokens -tokens inputfile
).Если вы сделаете это, вы увидите, что a
в вашем входе распознается как HexDigit
, а не как ID
.
Почему это происходит?Поскольку и HexDigit
, и ID
соответствуют входным данным a
, а ANTLR (как и большинство генераторов лексеров) разрешает неоднозначности в соответствии с правилом максимального мунка: когда несколько правил могут соответствовать текущему вводу, выбирается то, которое дает самое длинное соответствие(именно поэтому переменные с более чем одной буквой работают), а затем разрешает связи, выбирая ту, которая определена первой, в данном случае HexDigit
.
Обратите внимание, что лексеру не важно, какие правила лексераиспользуются парсером и когда.Лексер решает, какие токены создавать только на основе содержимого грамматики лексера, поэтому лексер не знает и не заботится о том, что парсер хочет ID
прямо сейчас.Он просматривает все правила, которые соответствуют, а затем выбирает одно из них в соответствии с правилом максимального munch, и все.
В вашем случае вы фактически никогда не используете HexDigit
в своей грамматике синтаксического анализатора, поэтому нет причин, почему вы 'я бы хотел, чтобы был создан токен HexDigit
.Поэтому HexDigit
не должно быть правилом лексера - это должно быть fragment
:
fragment HexDigit : [0-9a-fA-F];
Это также относится к другим вашим правилам, которые не используются в анализаторе, включая все ...Digit
правила.
PS: Ваше правило Number
никогда не будет совпадать из-за этих же правил.Возможно, вместо этого это должно быть правило синтаксического анализа (или другие числовые правила должны быть фрагментами, если вам все равно, какой тип числового литерала у вас есть).