Сравнение токенов, сгенерированных antlr

У меня есть следующее как часть моей грамматики (и здесь 'name' и 'value' просто статичны для простоты, на практике это не так):

test4 : 'name' CMPOP 'value';

CMPOP       :   EQUALS | NOTEQUALS;
EQUALS      :   '=';
NOTEQUALS   :   '!=';

Теперь я хочу по-разному обрабатывать разные CMPOP (возможно, с помощью переключателя). Есть ли способ получить int/enum-версию токена, лежащего в основе CMPOP (= или!=), пока я оцениваю выражение в реализации FilterListener? Я знаю, что могу получить строку с помощью getText(), но сравнение строк везде может быть медленным. например если у меня есть name=value, я вижу, что = TerminalNodeImpl и у него есть символ. Единственное, что здесь похоже, это свойство type, но оно, кажется, дает мне CMPOP.

public void exitTest4(@NotNull testParser.Test4Context ctx) {
    System.out.println(ctx.CMPOP().getSymbol().toString());
    int type = ctx.CMPOP().getSymbol().getType();
    System.out.println(type + "," + testParser.tokenNames[type]);
}

Дает мне:

[@1,4:4='=',<6>,1:4]
6,CMPOP

Я хочу сделать что-то вроде:

switch ( ctx.CMPOP().something() ) {
  EQUALS : //evaluate with = ; break
  NOTEQUALS : //evaluate with != ; break
}

Или я иду об этом неправильно? Должен ли я переместить это в правила парсера, а не в правила лексера, например: 'name' (EQUALS | NOTEQUALS) 'value'?

Я использую antlr4.


person naumcho    schedule 24.06.2014    source источник


Ответы (1)


У вас есть два основных варианта. Вы можете выбрать метод, который лучше всего подходит для вас.

Вариант 1. Измените CMPOP на правило синтаксического анализатора, а не на правило лексера.

cmpOp
  : EQUALS
  | NOTEQUALS
  ;

Преимущества:

  • Легко выполнить изменение
  • Легко поддерживать правило cmpOp, если оно когда-нибудь понадобится изменить
  • Улучшенная концептуальная группировка для EQUALS и NOTEQUALS в качестве операторов сравнения.

Вариант 2. Удалите правило CMPOP и вставьте набор в правила парсера.

Вместо этого замените весь код, который в настоящее время ссылается на CMPOP, на (EQUALS | NOTEQUALS).

Преимущества:

  • На 1 узел дерева синтаксического анализа меньше на оператор сравнения (незначительное снижение объема памяти, если это имеет значение для вашего случая)
person Sam Harwell    schedule 24.06.2014
comment
Как вы думаете, делать все это (переход на getType(), а не на getText()) в целом хорошая идея, или это может легко сломаться (например, в разных версиях)? Интересно, каков общий способ сделать это. - person naumcho; 24.06.2014
comment
Вам не нужно переключаться на getType(). Используйте if (ctx.EQUALS() != null) для проверки EQUALS (метод EQUALS() генерируется как часть класса контекста правила). - person Sam Harwell; 24.06.2014
comment
Я думаю, что возможность переключения становится более важной, особенно по мере роста числа возможных значений. Сейчас у меня есть 6 для cmpOp, но для некоторых других токенов у меня больше. - person naumcho; 25.06.2014
comment
Если вы перейдете к варианту 1, как вы все равно узнаете, равно оно или не равно? В контексте парсера нет getType. - person Jonathan.; 13.11.2014