java — Antlr4 — представляет синтаксические предикаты, которые проверяют произвольное количество токенов

В Antlr3 у меня есть следующая грамматика:

ruleA:
(ruleBStart) => ruleB
| ruleC
;

Для простоты предположим, что ruleB — это грамматика для оператора SELECT в SQL, но может быть вложено в произвольное количество LPAREN. Это легко представить в старой грамматике, просто сказав:

ruleBStart:
(LPAREN)* SELECT
;

В Antlr4, если бы я хотел сделать то же самое, я бы написал семантический предикат isRuleBStart() который может выглядеть так (псевдокод):

@parser::members{
public boolean isRuleBStart(int tokenNum)
{
int token = _input.LA(tokenNum);
if (token == EOF) return false; // handling EOF probably needs more work
if (token == SELECT) return true;
if (token == LPAREN) return isRuleBStart(tokenNum++);
return false;
}
}

И тогда в моей грамматике я бы сделал:

ruleA:
{isRuleBStart(1)}? ruleB
| ruleC
;

Это кажется проблематичным для меня, так как:

  1. Это включает в себя рекурсию в конструкции, которая уже Ходят слухи снижать производительность
  2. ruleBStart могло бы стать намного сложнее, если бы в правиле ruleBStart имелся произвольный набор различных токенов для проверки вместо простого повторения LPAREN
  3. Это связывает мой код с целевым языком. Поэтому, если бы я хотел опубликовать синтаксический анализатор на Java и C ++, мне пришлось бы повторно реализовать этот семантический предикат в обоих. (Я знаю, что можно тщательно программировать семантический предикат, чтобы один и тот же код работал на Java и C ++, но это не главное).

Поэтому я хочу спросить сообщество, существует ли правильный путь Antlr4 для достижения того же результата.

1

Решение

Нет необходимости в семантическом предикате с ANTLR4. Алгоритм ALL (*) будет выполнять неограниченный просмотр, если это необходимо, и, следовательно, не требует семантических предикатов или какого-либо сопоставимого взлома.

Так что, просто удалите этот предикат, и все должно работать.

0

Другие решения

Других решений пока нет …