3.2 Неоднозначні граматики
Граматики можуть бути неоднозначними.
Повернемося до граматики виразів. Ланцюжок Е+Е* Е має два породження:
1) Е Е + Е Е + Е * Е ;
2) Е Е * Е Е + Е * Е.
Їм відповідають два різних дерева виведення (рис. 3.2)
Рисунок
3.1-Приклад дерева розбору
Рисунок 3.2 - Дерева виведення для Е+Е* Е
Різниця полягає у способі групування виразів. Наприклад, 1, 2, 3 у першому випадку групуються як 1+(2*3)=7, у другому – як (1+2)*3=9.
Інший приклад.
Ланцюжок а+b може мати різні породження:
E E + E I + E a + E a + I a + b і
E E + E E + I I + I I + b a + b .
Обидва породження приводять до одного дерева розбору.
Таким чином, неоднозначність походить не від наявності багатьох породжень, а від існування двох і більше дерев розбору.
Є дві причини неоднозначності:
- не враховується пріоритет операторів;
- не враховується асоціативність операторів.
Рішенням проблеми неоднозначності може бути введення декількох змінних з різними можливостями зв'язування. Для прикладу можна ввести такі змінні.
Співмножник (factor) F, який не може бути розірваний на частини за допомогою “*” і “+”, які примикають зліва або справа.
Доданок (term) T , який не може бути розірваний оператором “+”. Наприклад, a*b не може бути розірваний оператором “+”, але може бути розірваний оператором “*”: a1*a*b=(a1*a)*b.
Вираз (expression) E – будь-який вираз, включаючи ті, які можуть бути розірвані за допомогою “* ” і “ + ”.
Мову, задану попередньою граматикою, можна за допомогою введених нами змінних E, T і F задати ще однією граматикою, яка є однозначною.
E
T
| E + T
,
T F | T * F ,
F I | (E) ,
I a | b | Ia | Ib | I0 | I1 .
Дана граматика враховує як лівоасоціативність, так і пріоритет операторів.
Розглянемо ще один приклад граматики для побудови умовного оператора.
stmt → if expr then stmt
| if expr then stmt else stmt
| other .
Ця граматика є неоднозначною, оскільки рядок
if expr1 then if expr2 then stmt1 else stmt2
має два дерева розбору (рис. 3.3).
Рисунок 3.3 - Два дерева розбору для stmt
В усіх мовах програмування з умовними інструкціями такого виду перевага віддається першому дереву розбору. Загальне правило говорить “зіставити кожне else найближчому ліворуч незайнятому then”. Це правило усунення неоднозначності може бути вбудоване безпосередньо в граматику. Основна ідея полягає у тому, що інструкція, що з'являється між then і else, повинна бути збалансованою (matched): вона може бути або повною інструкцією if-then-else, або інструкцією, що відрізняється від умовної.
Виходячи з цього, побудуємо граматику:
stmt → matched_stmt
| unmatched_ stmt ,
matched_stmt → if expr then matched_stmt else matched_stmt
| other ,
unmatched_stmt → if expr then stmt
| if expr then matched_stmt else unmatched_stmt .
Ця граматика генерує ту саму множину рядків, але дає тільки одне дерево розбору, яке зіставляє кожне else найближчому ліворуч незайнятому then.
Якщо хоча б одна граматика мови L однозначна, то L є однозначною мовою.
Мова виразів, породжувана попередніми граматиками, є однозначною.
Хоча породження не завжди унікальні, навіть якщо граматика однозначна, виявляється, що в однозначній граматиці і ліві, і праві породження унікальні.
Тому для дослідження неоднозначності можна брати, наприклад, тільки ліві породження.
Контекстовільна мова називається істотно неоднозначною, якщо всі її граматики неоднозначні.
Наведемо приклад істотно неоднозначної мови.
L = {an
bn
cm
dm
|
n,m≥1}
{an
bm
cm
dn
|
n,m≥1} ;
S AB | C ,
A aAb | ab ,
B cBd | cd ,
C aCd | aDd ,
B bDc | bc .
Усі ланцюжки цієї мови породжуються двома різними шляхами. Наприклад, для ланцюжка aabbccdd будуть отримані дерева розбору, зображені на рис. 3.4.
У даному прикладі всі ланцюжки породжуються двома різними шляхами.
Рисунок 3.4 - Дерева розбору для істотно неоднозначної мови
Для того щоб переконатися, що ланцюжок належить деякій мові, є два види аналізу.
Перший вид – спадний аналіз, або аналіз “зверху-вниз”, коли стартовий символ послідовно розгортається в ланцюжок. Популярність аналізаторів “зверху-вниз” обумовлена тим фактом, що побудувати ефективний аналізатор вручну простіше з використанням методу “зверху-вниз”.
Другий вид – висхідний аналіз, або аналіз “знизу- вгору”, коли ланцюжок послідовно згортається до стартового символа.
Позначимо корінь дерева через A. Наступні твердження рівносильні.
1 Згортка переводить ланцюжок w у A .
2 A
w
.
3 A
w
.
4 A
w .
5 Існує дерево розбору з коренем А і кроною w.
