- •5. Методи синтаксичного ааналізу
- •5.1. Спадний аналіз
- •5.1.1 Аналіз методом рекурсивного спуска
- •5.1.2 Предиктивні аналізатори
- •5.1.3 Діаграми переходів предиктивнх синтаксичних аналізаторів
- •5.1.4 Нерекурсивний предиктивнй аналіз
- •5.1.5 Побудова таблиць предиктивного аналізу
- •5.2. Висхідний синтаксичний аналіз
- •5.2.1 Основи
- •5.2.2 Обрізка основ
- •5.2.2 Стекова реалізація пз-аналізу
- •5.2.3 Активні префікси
- •5.2.4 Конфлікти в процесі пз-аналізу
5.1.2 Предиктивні аналізатори
У багатьох випадках акуратна розробка граматики, усунення з неї лівої рекурсії і її ліва факторизация дозволяють одержати граматику, яка може бути проаналізована синтаксичним аналізатором, що працює методом рекурсивного спуску). Для побудови предиктивного синтаксичного аналізатора ми повинні знати, яка з альтернатив продукций А ::= α1|α2|...|αn даного аналізованого нетермінала А породжує рядок, що починається з отриманого вхідного символу а. Інакше кажучи, правильна альтернатива повинна точно визначатися по першому породжуваному нею символу. Звичайно в мовах програмування керуючі конструкції відповідають цьому правилу. Наприклад, якщо є продукції:
stmt ::= if expr then stmt else stmt
| while expr do stmt
| begin stmt_list end
то ключові слова if, while й begin однозначно визначають можливу альтернативу для розглянутої інструкції stmt.
5.1.3 Діаграми переходів предиктивнх синтаксичних аналізаторів
Так само, як у розділі 3 діаграма переходів являла собою план лексичного аналізатора, при побудові предиктивного синтаксичного аналізатора ми можемо створити його план у вигляді діаграми переходів. При цьому ми виявимо ряд відмінностей між діаграмами переходів лексичного й предиктивного синтаксичного аналізаторів. У випадку синтаксичного аналізатора для кожного нетермінала є своя діаграма переходів. Мітки дуг являють собою токени й нетермінали. Перехід, позначений токеном (терміналом), означає, що ми повинні здійснити його, якщо даний токен є черговим символом у вхідному потоці; перехід, позначений нетерміналом, означає виклик процедури для цього нетермінала.
Для побудови діаграми переходів предиктивного синтаксичного аналізатора на основі граматики спочатку варто усунути з неї ліві рекурсії, а потім провести ліву факторизацию. Після цього для кожного нетермінала А виконується наступне.
Створюємо початковий й заключний стани.
Для кожної продукції А ::= X1X2 ... Xn створюємо шлях від початкового до заключного стану з дугами, позначеними как X1,X2, ...,Xn.
Предиктивнй синтаксичний аналізатор працює з діаграмою переходів у такий спосіб. Спочатку він перебуває в початковому стані стартового символу. Якщо після деяких дій синтаксичний аналізатор перебуває в стані s з дугою, позначеної терміналом а й такою, що веде в стан t, і якщо черговий вхідний символ являє собою а, то синтаксичний аналізатор переміщає вхідний курсор на одну позицію вправо й переходить у стан t. Якщо ж дуга позначена нетерміналом А, то синтаксичний аналізатор переходить у початковий стан для цього нетермінала, не переміщаючи при цьому вхідний курсор. По досягненні заключного стану для А синтаксичний аналізатор переходить у стан t, фактично "прочитавши" із вхідного потоку нетермінал А при переході зі стану s у стан t. І, нарешті, якщо зі стану s до стану t веде дуга, позначена як ε, те зі стану s синтаксичний аналізатор безпосередньо переходить у стан t, не переміщаючись по вхідному потоку.
Програма предиктивного синтаксичного аналізу, створена на основі діаграми переходів, намагається знайти відповідність кожному термінальному символу із вхідного потоку й здійснює потенційно рекурсивні виклики процедур для кожної дуги, позначеної нетерміналом. Нерекурсивна реалізація може бути отримана шляхом запису стану s у стек при вихідному переході з s по нетермінальному символу й зняття його зі стеку, коли досягнуто заключний стан для цього нетермінала.
Описаний вище підхід працює коректно, якщо в діаграмі переходів немає недетермінізму, тобто відсутні вузли з більш ніж одним переходом для одного вхідного символу. Як показано в наступному прикладі, неоднозначності можуть бути розв’язані спеціальним способом. Якщо ж усунути недетермінізм неможливо, то й побудувати предиктивнй синтаксичний аналізатор для цієї граматики неможливо (але можна побудувати синтаксичний аналізатор, що працює по методу рекурсивного спуска з відкатом і досліджує всі наявні можливості в пошуках коректної).
Приклад 5.2. На рис. 5.2 наведений набір діаграм переходів для граматики (4.11). Неоднозначності в цих діаграмах зв'язані тільки з ε-дугами. Розглянемо дуги, що виходять зі стану E'. Будемо вважати, що при одержанні із вхідного потоку символу ‘+’ ми маємо здійснити перехід по дузі, позначеної цим символом, а в противному випадку – ε-перехід (аналогічне правило варто використати й у стані T'). Таким чином, ми благополучно усуваємо неоднозначність і можемо написати програму предиктивного синтаксичного аналізатора для граматики (4.11).
Е ::= ТЕ'
Е' ::= +TЕ' | ε
T ::= FТ' (4.I1)
Т' ::= * FТ' | ε
F ::= (Е) | id
Рис. 5.2. Діаграма переходів для граматики (4.11)
Діаграми переходів можуть бути спрощені підстановкою одних діаграм в інші; Наприклад, на рис. 5.3а виклик E' себе ж можна замінити переходом у початок діаграми переходів для E'.
На рис. 5.3б показана отримана еквівалентна діаграма для E' яку ми можемо підставити замість переходу по Е' в діаграму для E на рис. 5.2, одержавши діаграму, зображену на рис. 5.3в. І, нарешті, ми бачимо, що в цій діаграмі перший і третій вузли еквівалентні, тому можна об'єднати їх, одержавши в результаті діаграму, показану на рис. 5.3г. Та ж технологія застосовна й до діаграм для Т и Т'. Повністю набір спрощених діаграм переходів наведений на рис. 5.4. Програма предиктивного розбору, реалізована на основі цих діаграм, працює на 20-25% швидше, ніж програма на основі набору діаграм, показаного на рис. 5.2.
ε T
в) г)
Рис. 5.3. Спрощена діаграма переходів
+
Рис. 5.4. Спрощена діаграма переходів для арифметичних виразів
