В практическом смысле, насколько серьезно
удалить левую рекурсию в ANTLR? Является
это showtopper в использовании ANTLR?
Я думаю, что у вас неправильное понимание левой рекурсии. Это свойство грамматики, а не генератора синтаксического анализатора или взаимодействия между генератором синтаксического анализатора и спецификацией. Это происходит, когда первый символ в правой части правила равен нетерминалу, соответствующему самому правилу.
Чтобы понять внутреннюю проблему, вам нужно кое-что узнать о том, как работает синтаксический анализатор с рекурсивным спуском (LL). В парсере LL правило для каждого нетерминального символа реализуется функцией, соответствующей этому правилу. Итак, предположим, у меня есть такая грамматика:
S -> A B
A -> a
B -> b
Тогда парсер будет выглядеть (примерно) так:
boolean eat(char x) {
// if the next character is x, advance the stream and return true
// otherwise, return false
}
boolean S() {
if (!A()) return false;
if (!B()) return false;
return true;
}
boolean A(char symbol) {
return eat('a');
}
boolean B(char symbol) {
return eat('b');
}
Однако что произойдет, если я поменяю грамматику следующим образом?
S -> A B
A -> A c | null
B -> b
Предположительно, я хочу, чтобы эта грамматика представляла такой язык, как c*b
. Соответствующая функция в парсере LL будет выглядеть так:
boolean A() {
if (!A()) return false; // stack overflow! We continually call A()
// without consuming any input.
eat('c');
return true;
}
Итак, у нас не может быть левой рекурсии. Перепишите грамматику как:
S -> A B
A -> c A | null
B -> b
и синтаксический анализатор изменяется следующим образом:
boolean A() {
if (!eat('c')) return true;
A();
return true;
}
(Отказ от ответственности: это мое элементарное приближение парсера LL, предназначенное только для демонстрационных целей по этому вопросу. В нем есть очевидные ошибки.)