Синтаксичний аналіз. Спадний аналіз. Предиктивний аналізатор. Висхідний аналіз, страница 12

Додаткова інформація впроваджується у стан шляхом перевизначення пунктів для включення термінального символа як другого компонента. Загальним видом пункту стає αβ, a], де Аαβ являє собою продукцію; а – термінал або маркер кінця рядка $. Такий об'єкт назвемо LR(1)-пунктом. Тут 1 означає довжину другого компонента, який називають попереднім переглядом(lookahead) пункту. Попередній перегляд не відіграє ролі у пункті вигляду αβ, a],  де βε, однак пункт вигляду α, a]  викликає згортання за продукцією Аα тільки тоді, коли черговий вхідний символ –  а. Отже, згортання за продукцією Аα виконується тільки для тих вхідних символів а, для яких α, a]  є  LR(1)-пунктом у стані на вершині стека. Множина таких а завжди буде підмножиною FOLLOW(A), але може бути і власною підмножиною.

Формально ми говоримо, що LR(1)-пункт αβ,a]допустимийдля активного префікса γ, якщо існує породження    S δAw δαβw, де

1)    γ=δα;

2)або а є першим символом w, або w являє собою ε,  а  а $.

Приклад 4.6

Розглянемо граматику

S ВВ ,

B aВ|b .

Є праве породження SaaBab aaaBab. Ми бачимо, що пункт [B→a•B, a] допустимий для активного префікса γ=ааа, вважаючи у наведеному вище визначенні δ=аа, А=B, w=ab, α=a і β=В.

Є також праве породження SBaBBaaB, відповідно до якого пункт [B→a•B, $] допустимий для активного префікса Ваа.  

Метод побудови системи множин допустимих LR(1)-пунктів, по суті, той самий, що й спосіб побудови канонічної системи множин LR(0)-пунктів. Нам необхідно внести зміни тільки у дві функції – closure і goto.

Щоб розібратися у новому визначенні операції closure, розглянемо пункт вигляду [A→a•Bβ, a] з множини пунктів, допустимих для деякого активного префікса γ. Тоді існує праве породження SδAaxδαAβax, де γ=δα. Припустимо, що βaxпороджує термінальний рядок by. Тоді для кожної продукції вигляду B→η з деяким  η ми   одержуємо   породження    SγBbyγηby.   Отже,   пункт [A→ •η, b] допустимий для активного префікса γ. Відмітимо, що bможе бути першим терміналом, виведеним з β. Можливо також, що з β виводиться ε у породженні βAxby, і b, отже, може бути терміналом а. Резюмуючи обидві можливості, ми говоримо, що bможе бути будь-яким терміналом з FIRST(βAx). Відмітимо, що х не може містити перший термінал bу, так що FIRST(βax)= =FIRST(βa). Тепер представимо спосіб побудови множин LR(1)-пунктів.

Алгоритм 4.9 Побудова множин LR(1)-пунктів

function  closure(I);

begin

      repeat

for кожного пункту α•Bβ, a]I, кожної продукції Вγ із G' і кожного термінала b із FIRST(βa), такого, що [B→• γ, b]Ido додати

 [B→• γ, b] в I;

until пунктів для додавання в I більше немає;

      return I;

end;

function  goto (I, X);

begin

Нехай   J –  множина пунктів   αXβ, a], таких,   що   α•Xβ, a]I;

return closure (J);

end;

procedure items (G’);

begin

      C:={closure ( {[S’→S, $]} )};

            repeat

for  кожної множини  пунктів IC  і  кожного символа граматики X,   таких,   що  goto (I, X) не  порожньо і не  належить C do додати   goto(I,X)  у  C

until  множин пунктів для додавання в C більше  немає

end

Розглянемо таку розширену граматику:

S' ВВ ,

S CC ,(4.6)

C cC|d .  

Почнемо з обчислення замикання {[S'S, $]}. Для цього зіставимо пункт {[S'S, $]} з пунктом α•Bβ,a] із процедури closure;таким чином, A = S', α = ε, B=S, β = εі a = $. Функція closureвимагає додати [B →γ, b] у FIRST(βa) для кожної продукції В γ і термінала b. У нашій граматиці В γ відповідає S CC, і оскільки β дорівнює ε, а а$, bможе бути тільки $. Таким чином, ми додаємо [S'CC, $]}.

Далі ми продовжуємо обчислення замикання, додаючи всі пункти [C →γ, b] для b з FIRST(C$). Зіставляючи [S →CC, $] і [A → α•Bβ,a], одержуємо A=S, α=ε, B = C, β = C і a = $. Оскільки C не породжує порожній рядок, FIRST(C$)= FIRST(C). Тому що FIRST(C)  містить термінали с і d, ми додаємо пункти [C →cC, c], [C →cC, d], [C →d, c]і [C →d, d]. Ніякі з нових пунктів не мають нетерміналів безпосередньо праворуч від точки, так що ми завершуємо на цьому побудову першої множини LR(1)-пунктів. Початкова множина пунктів така:

I0 :   S'S, $ ,

S →CC, $,

C →cC, c| d ,

C →d,c| d .

Тут для зручності запису опущені квадратні дужки, а також для представлення двох пунктів – [C →cC, c] і [C→cC, d] –  використовується позначення [C→ cC, c|d].