Дана контекстно-свободная грамматика G с правилами S -> SS | "a" S "b" | ε; определите язык, который она порождает, докажите или опровергните её неоднозначность, приведите эквивалентный детерминированный автомат (если существует) или докажите, что язык не является детерминируемым (LR(1)/DFA), и предложите способ преобразования грамматики для парсинга в практическом компиляторе
Грамматика: S→SS∣a S b∣ε
S \to SS \mid a\,S\,b \mid \varepsilon S→SS∣aSb∣ε 1) Язык, порождённый грамматикой. L(G)={w∈{a,b}∗∣#a(w)=#b(w) и для каждой позиции u (префикс w) #a(u)≥#b(u)},
L(G)=\{w\in\{a,b\}^*\mid \#_a(w)=\#_b(w)\ \text{и для каждой позиции }u\text{ (префикс }w)\ \#_a(u)\ge\#_b(u)\}, L(G)={w∈{a,b}∗∣#a(w)=#b(w)идлякаждойпозицииu (префиксw)#a(u)≥#b(u)},
то есть язык корректно сбалансованных скобок одного типа (аналог Dyck-1, ставим \(a='('\), \(b=')'\)). Краткое объяснение: правило aSbaSbaSb даёт вложенные пары a…ba\ldots ba…b, правило SSSSSS — конкатенацию корректных фрагментов, ε\varepsilonε — пустую строку. Все и только корректно сбалансированные строки получаются. 2) Неоднозначность грамматики. Грамматика неоднозначна. Контрпример: w=abababw=abababw=ababab (эквивалентно "()()()"). Две разные левосторонние вывoдные последовательности (показываю схематично): Первый вариант (дерево вида ((SS)S)((SS)S)((SS)S)): S⇒SS⇒SS S⇒(aSb) S S⇒(aεb) S S⇒ab S S⇒ab (aSb) S⇒ab (aεb) S⇒abab S⇒abab (aSb)⇒ababab.
S\Rightarrow SS \Rightarrow SS\,S \Rightarrow (aSb)\,S\,S \Rightarrow (a\varepsilon b)\,S\,S \Rightarrow ab\,S\,S \Rightarrow ab\,(aSb)\,S \Rightarrow ab\,(a\varepsilon b)\,S \Rightarrow abab\,S \Rightarrow abab\,(aSb)\Rightarrow ababab. S⇒SS⇒SSS⇒(aSb)SS⇒(aεb)SS⇒abSS⇒ab(aSb)S⇒ab(aεb)S⇒ababS⇒abab(aSb)⇒ababab. Второй вариант (дерево вида (S(SS))(S(SS))(S(SS))): S⇒SS⇒S SS⇒S (aSb) S⇒S (aεb) S⇒S ab S⇒(aSb) ab S⇒(aεb) ab S⇒ab ab S⇒ab ab (aSb)⇒ababab.
S\Rightarrow SS \Rightarrow S\,SS \Rightarrow S\,(aSb)\,S \Rightarrow S\,(a\varepsilon b)\,S \Rightarrow S\,ab\,S \Rightarrow (aSb)\,ab\,S \Rightarrow (a\varepsilon b)\,ab\,S \Rightarrow ab\,ab\,S \Rightarrow ab\,ab\,(aSb)\Rightarrow ababab. S⇒SS⇒SSS⇒S(aSb)S⇒S(aεb)S⇒SabS⇒(aSb)abS⇒(aεb)abS⇒ababS⇒abab(aSb)⇒ababab. Получены разные деревья вывода для одного слова ⇒ грамматика неоднозначна. 3) Регулярность и детерминируемость. - Язык не является регулярным. Простая аргументация: для любого ppp (pumping length) строка apbpa^p b^papbp принадлежит L(G)L(G)L(G), но по лемме о накачке регулярных языков нельзя накачать часть только из блока aaa так, чтобы равенство чисел aaa и bbb сохранялось — противоречие. - Язык является детерминируемым в смысле детерминированного КСЯ (DPDA) и является LR(1) (и даже LL(1)). Это стандартный детерминированный язык скобочной последовательности одного типа. DPDA (одно состояние qqq, маркер дна Z0Z_0Z0, символ стека AAA): δ(q,a,Z0)=(q,AZ0),δ(q,a,A)=(q,AA),δ(q,b,A)=(q,ε),при конце входа: если стек Z0 — принять, иначе отклонить.
\begin{aligned} &\delta(q,a,Z_0)=(q,AZ_0),\qquad \delta(q,a,A)=(q,AA),\\ &\delta(q,b,A)=(q,\varepsilon),\\ &\text{при конце входа: если стек }Z_0\text{ — принять, иначе отклонить.} \end{aligned} δ(q,a,Z0)=(q,AZ0),δ(q,a,A)=(q,AA),δ(q,b,A)=(q,ε),приконцевхода: еслистекZ0 — принять, иначеотклонить.
На aaa — детерминированно пушим AAA; на bbb — если верх стека AAA, попаем; иначе — ошибка. Это детерминированный автомат-стек, принимающий L(G)L(G)L(G). 4) Предложение по преобразованию грамматики для парсинга в компиляторе. Заменить неоднозначную грамматику на эквивалентную однозначную (и пригодную для LL/LR-парсинга), например: S→a S b S∣ε.
S\to a\,S\,b\,S \mid \varepsilon. S→aSbS∣ε.
Эта грамматика однозначна и описывает тот же язык: любая непустая сбалансированная строка представляется как первая пара a…ba\ldots ba…b с вложенным внутри SSS и затем следует (конкатенируется) ещё один SSS. Она подходит для рекурсивного спуска (LL(1)) и для LR(1)-парсеров. Для практической реализации: - использовать рекурсивный спуск по правилу: если lookahead = aaa, потребовать aaa, вызвать S, ожидать bbb, затем рекурсивно вызвать S; если lookahead = bbb или EOF — возвращать ε\varepsilonε; - либо строить LR(1)-таблицу по этой грамматике (она не содержит конфликтов). Вывод: грамматика порождает язык корректно сбалансованных a,ba,ba,b-строк (Dyck-1), сама неоднозначна, язык не регулярный но является детерминируемым КСЯ (DPDA, LR(1)). Для парсинга замените грамматику на, например, S→aSbS∣εS\to aSbS\mid\varepsilonS→aSbS∣ε.
S→SS∣a S b∣ε S \to SS \mid a\,S\,b \mid \varepsilon
S→SS∣aSb∣ε
1) Язык, порождённый грамматикой.
L(G)={w∈{a,b}∗∣#a(w)=#b(w) и для каждой позиции u (префикс w) #a(u)≥#b(u)}, L(G)=\{w\in\{a,b\}^*\mid \#_a(w)=\#_b(w)\ \text{и для каждой позиции }u\text{ (префикс }w)\ \#_a(u)\ge\#_b(u)\},
L(G)={w∈{a,b}∗∣#a (w)=#b (w) и для каждой позиции u (префикс w) #a (u)≥#b (u)}, то есть язык корректно сбалансованных скобок одного типа (аналог Dyck-1, ставим \(a='('\), \(b=')'\)).
Краткое объяснение: правило aSbaSbaSb даёт вложенные пары a…ba\ldots ba…b, правило SSSSSS — конкатенацию корректных фрагментов, ε\varepsilonε — пустую строку. Все и только корректно сбалансированные строки получаются.
2) Неоднозначность грамматики.
Грамматика неоднозначна. Контрпример: w=abababw=abababw=ababab (эквивалентно "()()()"). Две разные левосторонние вывoдные последовательности (показываю схематично):
Первый вариант (дерево вида ((SS)S)((SS)S)((SS)S)):
S⇒SS⇒SS S⇒(aSb) S S⇒(aεb) S S⇒ab S S⇒ab (aSb) S⇒ab (aεb) S⇒abab S⇒abab (aSb)⇒ababab. S\Rightarrow SS \Rightarrow SS\,S \Rightarrow (aSb)\,S\,S \Rightarrow (a\varepsilon b)\,S\,S \Rightarrow ab\,S\,S \Rightarrow ab\,(aSb)\,S \Rightarrow ab\,(a\varepsilon b)\,S \Rightarrow abab\,S \Rightarrow abab\,(aSb)\Rightarrow ababab.
S⇒SS⇒SSS⇒(aSb)SS⇒(aεb)SS⇒abSS⇒ab(aSb)S⇒ab(aεb)S⇒ababS⇒abab(aSb)⇒ababab.
Второй вариант (дерево вида (S(SS))(S(SS))(S(SS))):
S⇒SS⇒S SS⇒S (aSb) S⇒S (aεb) S⇒S ab S⇒(aSb) ab S⇒(aεb) ab S⇒ab ab S⇒ab ab (aSb)⇒ababab. S\Rightarrow SS \Rightarrow S\,SS \Rightarrow S\,(aSb)\,S \Rightarrow S\,(a\varepsilon b)\,S \Rightarrow S\,ab\,S \Rightarrow (aSb)\,ab\,S \Rightarrow (a\varepsilon b)\,ab\,S \Rightarrow ab\,ab\,S \Rightarrow ab\,ab\,(aSb)\Rightarrow ababab.
S⇒SS⇒SSS⇒S(aSb)S⇒S(aεb)S⇒SabS⇒(aSb)abS⇒(aεb)abS⇒ababS⇒abab(aSb)⇒ababab.
Получены разные деревья вывода для одного слова ⇒ грамматика неоднозначна.
3) Регулярность и детерминируемость.
- Язык не является регулярным. Простая аргументация: для любого ppp (pumping length) строка apbpa^p b^papbp принадлежит L(G)L(G)L(G), но по лемме о накачке регулярных языков нельзя накачать часть только из блока aaa так, чтобы равенство чисел aaa и bbb сохранялось — противоречие.
- Язык является детерминируемым в смысле детерминированного КСЯ (DPDA) и является LR(1) (и даже LL(1)). Это стандартный детерминированный язык скобочной последовательности одного типа.
DPDA (одно состояние qqq, маркер дна Z0Z_0Z0 , символ стека AAA):
δ(q,a,Z0)=(q,AZ0),δ(q,a,A)=(q,AA),δ(q,b,A)=(q,ε),при конце входа: если стек Z0 — принять, иначе отклонить. \begin{aligned}
&\delta(q,a,Z_0)=(q,AZ_0),\qquad \delta(q,a,A)=(q,AA),\\
&\delta(q,b,A)=(q,\varepsilon),\\
&\text{при конце входа: если стек }Z_0\text{ — принять, иначе отклонить.}
\end{aligned}
δ(q,a,Z0 )=(q,AZ0 ),δ(q,a,A)=(q,AA),δ(q,b,A)=(q,ε),при конце входа: если стек Z0 — принять, иначе отклонить. На aaa — детерминированно пушим AAA; на bbb — если верх стека AAA, попаем; иначе — ошибка. Это детерминированный автомат-стек, принимающий L(G)L(G)L(G).
4) Предложение по преобразованию грамматики для парсинга в компиляторе.
Заменить неоднозначную грамматику на эквивалентную однозначную (и пригодную для LL/LR-парсинга), например:
S→a S b S∣ε. S\to a\,S\,b\,S \mid \varepsilon.
S→aSbS∣ε. Эта грамматика однозначна и описывает тот же язык: любая непустая сбалансированная строка представляется как первая пара a…ba\ldots ba…b с вложенным внутри SSS и затем следует (конкатенируется) ещё один SSS. Она подходит для рекурсивного спуска (LL(1)) и для LR(1)-парсеров. Для практической реализации:
- использовать рекурсивный спуск по правилу: если lookahead = aaa, потребовать aaa, вызвать S, ожидать bbb, затем рекурсивно вызвать S; если lookahead = bbb или EOF — возвращать ε\varepsilonε;
- либо строить LR(1)-таблицу по этой грамматике (она не содержит конфликтов).
Вывод: грамматика порождает язык корректно сбалансованных a,ba,ba,b-строк (Dyck-1), сама неоднозначна, язык не регулярный но является детерминируемым КСЯ (DPDA, LR(1)). Для парсинга замените грамматику на, например, S→aSbS∣εS\to aSbS\mid\varepsilonS→aSbS∣ε.