Чому під час проектування компілятора слід усунути ліву рекурсію у граматиках? Я читаю, що це тому, що це може спричинити нескінченну рекурсію, але чи не так це і для правильної рекурсивної граматики?
Чому під час проектування компілятора слід усунути ліву рекурсію у граматиках? Я читаю, що це тому, що це може спричинити нескінченну рекурсію, але чи не так це і для правильної рекурсивної граматики?
Відповіді:
Ліві рекурсивні граматики - це не обов'язково погана річ. Ці граматики легко розбираються, використовуючи стек, щоб відслідковувати вже проаналізовані фрази, як це відбувається у LR-аналізаторі .
Нагадаємо, що ліве рекурсивне правило граматики CF має вигляд:
з - елемент V і β - елемент V ∪ Σ . (Дивіться повне формальне визначення кортежу ( V , Σ , R , S ) там ).
Зазвичай - це фактично послідовність терміналів і нетерміналів, і існує інше правило α, де α не відображається в правій частині.
Щоразу, коли граматичний аналізатор граматики отримує новий термінал (від лексеру), цей термінал висувається на вершину стека: ця операція називається зсувом .
Кожен раз, коли праву частину правила узгоджується групою послідовних елементів у верхній частині стека, ця група замінюється одним елементом, що представляє щойно збіжену фразу. Ця заміна називається скороченням .
При правильних рекурсивних граматиках стек може зростати нескінченно до тих пір, поки не відбудеться зменшення, таким чином, досить різко обмеживши можливості аналізу. Однак ліві рекурсивні дозволить компілятору генерувати скорочення раніше (насправді якнайшвидше). Додаткову інформацію див. У статті wikipedia .
Розглянемо це правило:
example : 'a' | example 'b' ;
Тепер розглянемо аналізатор LL, який намагається співставити невідповідний рядок, як 'b'
це правило. Оскільки 'a'
він не відповідає, він спробує співставити example 'b'
. Але для цього він повинен відповідати example
... що саме це намагалося зробити в першу чергу. Він може застрягнути, намагаючись назавжди побачити, чи може він відповідати, тому що він завжди намагається співставити той самий потік жетонів з тим же правилом.
Щоб цього не допустити, вам доведеться або розібратися праворуч (що досить рідко, наскільки я бачив, і замість цього зробить правильну рекурсію), штучно обмежте кількість дозволених вкладень або збігайте лексема перед початком рекурсії, тому завжди є базовий випадок (а саме там, де всі жетони були використані та ще немає повного збігу). Оскільки право-рекурсивне правило вже третє, це не має тієї ж проблеми.
(Я знаю, що це питання вже досить давнє, але якщо інші люди мають те саме питання ...)
Ви запитуєте в контексті рекурсивних аналізаторів спуску? Наприклад, для граматики expr:: = expr + term | term
, чому щось подібне (зліва рекурсивна):
// expr:: = expr + term
expr() {
expr();
if (token == '+') {
getNextToken();
}
term();
}
проблематично, але чи не це (правильно рекурсивно)?
// expr:: = term + expr
expr() {
term();
if (token == '+') {
getNextToken();
expr();
}
}
Схоже, самі обидві версії expr()
виклику. Але важлива відмінність - це контекст - тобто поточний маркер при здійсненні цього рекурсивного дзвінка.
У лівому рекурсивному випадку expr()
постійно дзвонить собі з тим самим ознакою і жодного прогресу не досягається. У правому рекурсивному випадку він витрачає частину входу в дзвінок до term()
та маркер PLUS, перш ніж перейти до виклику expr()
. Тож у цей момент рекурсивний виклик може викликати термін, а потім припиняти, перш ніж знову доходити до тесту if.
Наприклад, розгляньте синтаксичний аналіз 2 + 3 + 4. Лівий рекурсивний синтаксичний синтаксичний виклик expr()
нескінченно затримується на першому жетоні, тоді як правий рекурсивний аналізатор споживає "2 +" перед тим, як expr()
знову зателефонувати . Другий дзвінок expr()
відповідає "3 +" та дзвінки expr()
лише з 4-х, що залишилися. 4 збігу на термін, і синтаксичний аналіз завершується без жодних викликів expr()
.
З посібника Bison:
"Будь-який тип послідовності можна визначити, використовуючи або ліву рекурсію, або праву рекурсію, але ви завжди повинні використовувати ліву рекурсію , оскільки вона може аналізувати послідовність будь-якої кількості елементів із обмеженим простором стека. Права рекурсія використовує простір на стеку Bison у пропорція кількості елементів у послідовності, оскільки всі елементи повинні бути зміщені на стек, перш ніж правило можна застосувати навіть один раз. Для подальшого пояснення цього див. алгоритм Бізона Парсера ".
http://www.gnu.org/software/bison/manual/html_node/Recursion.html
Отже, це залежить від алгоритму аналізатора, але як зазначено в інших відповідях, деякі парсери можуть просто не працювати з лівою рекурсією