Вопрос #1610249

Дана неоднозначная контекстно‑свободная грамматика S -> 'a' S 'a' | 'a' S 'b' | ε; покажите два различных дерева вывода для строки "aaab", обсудите способы удаления неоднозначности и последствия для парсинга в компиляторах

Ответы
1


Короткий ответ сначала: на самом деле для строки "aaab" грамматика даёт единственное дерево вывода. Ниже — разбор, дерево, почему двух разных дерев нет, и краткие способы удаления неоднозначности + последствия для парсеров.
1) Разбор и вывод строки. Пусть строка \(w=\text{"aaab"}\), \(|w|=4\). Если применено \(k\) нетерминальных правил вида \(S\to aSx\) (где \(x\in\{a,b\}\)), то длина выводимой строки равна \(2k\). Для \(|w|=4\) следует \(k=2\). Значит структура вывода обязана быть
\[
S\Rightarrow a\,S_1\,x_1,\qquad S_1\Rightarrow a\,S_2\,x_2,\qquad S_2\Rightarrow\varepsilon,
\]
и итоговая строка имеет вид \(a\,a\,x_2\,x_1\). Чтобы получить "aaab" нужно \(x_2=a,\ x_1=b\). Это даёт единственную последовательность применений:
\[
S \Rightarrow a S b \Rightarrow a\bigl(a S a\bigr)b \Rightarrow a(a\varepsilon a)b = \text{aaab}.
\]
2) Дерево вывода (единственное) в текстовом виде:
S
├─ 'a'
├─ S
│ ├─ 'a'
│ ├─ S (ε)
│ └─ 'a'
└─ 'b'
(В математической форме: \(\,S\Rightarrow a\,S\,b\Rightarrow a\,(a\,S\,a)\,b\Rightarrow a\,(a\,\varepsilon\,a)\,b=\text{aaab}\).)
3) Почему нельзя получить второе дерево для "aaab". Для фиксированного \(k\) каждая последовательность выборов правых терминалов \(x_k,\dots,x_1\in\{a,b\}\) даёт различную суффиксную часть строки \(x_k\dots x_1\). Следовательно разные деревья (разные комбинации применённых правил) приводят к разным строкам — для данной строки выбор однозначен, значит нет неоднозначности для "aaab".
4) Общие способы удаления/обхода неоднозначности и последствия для парсинга:
- Переписать грамматику в однозначную форму (если это возможно) — явный, но иногда трудоёмкий метод; обычно требуется реформулировать синтаксис языка.
- Ввести явные приоритеты/ассоциативность (правила разрешения конфликтов) — часто применяется в парсерах типа yacc/bison.
- Использовать алгоритмы, допускающие неоднозначность: GLR, Earley — они строят лес выводов (packed parse forest) и позволяют работать с неоднозначными грамматиками, но сложность и расход памяти выше.
- На этапе компилятора обычно стремятся к однозначной грамматике, потому что неоднозначность порождает неоднозначное AST → неоднозначность семантики; если невозможно убрать, применяют дополнительные семантические правила для разрешения.
Краткая практическая рекомендация: для синтаксиса языков программирования предпочтительно переписать грамматику в класс LL/LR-пригодную или явно задать правила разрешения конфликтов; при необходимости анализа неоднозначных конструкций применять GLR/Earley и затем семантически распутывать лес выводов.

Минимум 10 символов
Прямой эфир