У вас есть несколько правил лексера, которые будут соответствовать вводу ==
или !=
. ANTLR (как и большинство генераторов лексеров) разрешает неоднозначности в правилах лексеров, сначала выбирая те из них, которые дают самое длинное совпадение (в этом случае все правила приводят к совпадению длины 2), а затем разрешая связи, выбирая единицу это идет первым в грамматике. Поэтому, когда лексер видит ==
или !=
, он всегда генерирует токен типа STRING_RELATIONAL_OPERATORS
.
Обратите внимание, что лексеру не важно, какие токены парсер хочет сейчас - лексер функционирует независимо от парсера. Он только смотрит на текущий ввод и определенные правила лексера, чтобы решить, какой тип токена создать. Таким образом, одна и та же последовательность символов всегда будет создавать один и тот же вид токена.
Чтобы исправить свою грамматику, вы должны определить свои правила лексера, чтобы они не перекрывались, а затем сгруппировать их, как вам нравится в правилах синтаксического анализатора. Таким образом, вы можете иметь одно правило лексера на оператор (возможно, неявно, используя строковые литералы в правилах синтаксического анализатора), а затем просто использовать ('==' | '!=' | ...)
в синтаксическом анализаторе.
Я бы также рекомендовал иметь только одно правило синтаксического анализа для реляционных выражений. Прямо сейчас у вас есть по одному для каждого типа, чтобы запретить сравнение выражений разных типов, но этот подход не масштабируется (что вы будете делать, когда вводите переменные, например?). Вместо этого вам следует просто разрешить некорректно выраженное выражение в анализаторе, а затем отклонить его в средстве проверки типов, которое вы пишете отдельно.
PS: для того, чтобы найти эти типы проблем в лексере, это помогает напечатать поток токенов, который был сгенерирован для данного ввода. Вы можете достичь этого, перебирая поток токенов в своем Java-коде или запуская grun YourGrammarName tokens -tokens yourInputFile
в командной строке.