Когда вы говорите, что «моя программа всегда будет идти к первому идентификатору», я предполагаю, что вы имеете в виду, что где-то еще в вашей грамматике у вас есть такое правило:
expr: ...
| bool
| float
;
И это всегда будет входить в правило bool
, поскольку оно идет первым и соответствует тем же токенам, что и float
. Как правило, нет смысла иметь две альтернативы в правиле, которые расширяются до одних и тех же токенов.
Вы можете сделать bool
и float
совпадением, только если ID
содержится в соответствующей карте, используя предикаты, но это, как правило, не очень хорошая идея. Гораздо более распространенным подходом является создание единой карты, содержащей записи для всех переменных независимо от их типа.
PS: На более общем замечании похоже, что вы пытаетесь вычислять выражения непосредственно в синтаксическом анализаторе (по крайней мере, имя вашего возвращаемого значения предполагает, что вы пытаетесь вычислить значение выражения). Обратите внимание, что этот подход не будет работать за пределами простого калькулятора. Как только вы введете какой-либо поток управления (вызовы функций, операторы if, циклы), вы обнаружите, что невозможно контролировать, когда и как часто должен выполняться код в действиях (он всегда будет выполняться ровно один раз, когда код разбирается). Вместо того, чтобы делать это таким образом, ваш синтаксический анализатор должен просто создать дерево или байт-код, который затем можно выполнить на отдельном шаге.