Порождающие грамматики

Теория

Как уже отмечалось, классическая теория формальных языков изучает прежде всего синтаксис языка. Она вводит математическую модель синтаксиса, которая описывает механизмы порождения и распознавания "правильно построенных" цепочек. В этом разделе мы рассмотрим первый из этих механизмов. Задать такой механизм - значит описать некую процедуру, позволяющую вывести (или, как обычно говорят, породить) произвольную цепочку языка согласно определенному конечному множеству правил. Последнее очень важно: язык может быть бесконечным, но множество правил, с помощью которых выводятся его цепочки, обязано быть конечным. Заметим, что не каждый язык может быть представлен таким образом, но мы в рамках этого учебника будем рассматривать только такие языки, т .е. языки, синтаксис которых задается конечным множеством правил. Эти языки, вообще говоря бесконечные, но допускающие конечное описание, называют перечислимыми. Таким образом, мы рассматриваем только перечислимые языки.

Классическим способом определения языков через порождающую процедуру является определение их с помощью порождающих грамматик, или грамматик Хомспого.

Порождающая грамматика позволяет выводить (порождать) цепочки языка из некоторой начальной цепочки с помощью определенных правил замены (или правил подстановки, правил переписывания). Порождение есть пошаговый процесс, в котором на каждом шаге из цепочки, уже полученной на предыдущем шаге (в частности, из начальной), можно путем применения к ней правил замены получить новую цепочку. Именно так мы действуем, решая какую-нибудь матем атическую задачу, например выполняя дифференцирование и переходя от одной формулы к другой с помощью таблицы производных. Порождающая грамматика (далее просто грамматика) задается упорядоченной четверкой G = (V, N, S, Р), в которой V - алфавит, называемый терминальным алафавитом; N - алфавит, называемый нетерминальным алфафавитом, причем пересечение V и N пусто; S - выделенный символ нетерминального алфавита, называемый аксиомой; Р - конечное множество правил вывода, или продукций. Каждое правило вывода является упорядоченной парой (α,β) цепочек в алфавите V U N, причем цепочка а должна содержать вхожденuе хотя бы одного символа нетерминального алфавита; цепочку а называют левой, цепочку β - правой частью правила вывода.

Правило вывода принято записывать в таком виде:

α → β,

разделяя левую и правую части "стрелкой", которая рассматривается как "метасимвол" и не принадлежит ни одному из алфавитов грамматики. Буквы терминального алфавита грамматики называют терминальными символами (или просто терминалами); буквы нетерминального алфавита называют нетерминальными символами (или нетерминалами). Любую цепочку в терминальном (нетерминальном) алфавите называют терминальной (нетерминальной) цепочкой. Алфавит V ∪ N называют объединенным алфавитом грамматики G.

Пример 7.3. Четверка

G0 = ({а,и}, {S,A,B}, S, {S → аАВb,аА → аВ, аВ → аВа, аА → аа, аВb → ааbb, аВа → аbВbа, Вb → Аb})

задает грамматику с терминальным алфавитом V = {а, b}, с нетерминальным алфавитом N = {S, А, В}, с аксиомой S и множеством правил вывода Р, элементы которого перечислены в фигурных скобках после аксиомы. Обычно ради наглядности правила вывода грамматики выписывают отдельно:

S → аАВb, аА → аВ, аВ → аВа, аА → аа, аВb → ааbb, аВа → аbВЬа, Вb → Аb.

Замечание 7.1. Нам будет удобно условиться о некоторых обозначениях, которыми мы все время будем пользоваться, имея дело с грамматиками. Терминалы будем обозначать малыми латинскими буквами из начала латинского алфавита: а, b, с и т.д.; нетерминалы - большими латинскими буквами из начала и середины латинского алфавита: А, В, С, S, Т и т.д.; терминальные цепочки (т.е. слова в терминальном алфавите) - малыми латинскими буквами из середины и конца латинского алфавита: s, t, р, q, х, у, z и т.д.; цепочки в объединенном алфавите - малыми греческими буквами. Наконец, большими латинскими буквами из конца алфавита будем обозначать символы объединенного алфавита или пустую цепочку. #

Определение грамматики указывает пока только на то, что следует фиксировать, чтобы задать какую-либо грамматику. А именно следует фиксировать два непересекающихся алфавита, выделив в одном из них символ, названный аксиомой, а также конечное множество правил вывода. Но мы еще не знаем, каким образом "работает" грамматика как инструмент порождения (и преобразования) слов. Чтобы это понять, нужно определить важнейшее понятие выводимости в данной грамматике.

Неформально каждое правило вывода грамматики трактуется как "правило замены", разрешающее произвольное вхождение левой части правила в некоторую цепочку в объединенном алфавите заменить его правой частью, получив (или выведя) тем самым новую цепочку. Так, для примера 7.3 мы можем от цепочки S, используя правило S → аАВb, перейти к цепочке аАВb. В этой цепочке есть вхождение левой части правил аА → аВ и аА → аа, а также левой части правила Вb → Аb. Можно использовать любое из них (но какое-нибудь одно!): если мы заменим (в данном случае единственное) вхождение цепочки аА правой частью правила аА → аВ, то получим цепочку аВВb и т.д. Таким образом мы и строим так называемые выводы - последовательности цепочек, в которых каждый последующий член получается из предыдущего заменой, подобной только что рассмотренной.

Определение 7.6. Цепочка б непосредственно выводима в грамматике G из цепочки γ (или из γ непосредствеиио выводится δ), если существуют такие цепочки σ и р и такое правило вывода α → β из Р, что γ = σαр (т.е. существует вхождение левой части правила вывода в цепочку γ), а δ = σβр.

Бинарное отношение на множестве цепочек в объединенном алфавите, которое состоит из всех упорядоченных пар (γ, δ), таких, что вторая цепочка непосредственно выводится из первой, называют отношением непосредственной выводимости. Его будем обозначать символом 1-а, опуская зачастую имя грамматики: γ ⊢ δ. В этом случае говорят также, что правило α → β применяется к цепочке γ ( и что цепочка δ получена применением правила α → β к цепочке γ или, что равносильно, в результате замены данного вхождения левой части правила α → β его правой частью).

В общем случае, если левая часть правила вывода входит в данную цепочку, говорят, что правило применимо к этой цепочке (или имеет место применимость правила вывода к цепочке). Если же левая часть правила вывода не входит в цепочку, то говорят, что правило не применимо к данной цепочке.

Рефлексuвно-транэuтuвное замыкание отношения непосредственной выводимости обозначаем ⊢*G (опять-таки опуская имя грамматики G, если это не приводит к недоразумению: ⊢*) и называем отношением выводимости. Иначе говоря, выводимость цепочки δ из цепочки γ, γ⊢*G δ, в грамматике G имеет место, по определению, тогда и только тогда, когда найдутся такие слова α0 = γ, α1, ... , αn = δ, где n ≥ 0, что

α0G α1G...⊢Gαn-1Gαn.

Для данной цепочки γ в объединенном алфавите, если к ней применимо хотя бы одно правило вывода рассматриваемой грамматики, существует в общем случае не одна, а много цепочек, непосредственно выводимых из нее. Эта неоднозначность связана с двумя факторами. Во-первых, может существовать несколько разных правил вывода, применимых к цепочке γ. Так, для грамматики примера 7.3 к цепочке аАаВb применимы все правила грамматики, кроме первого. Тогда любая цепочка, полученная применением к указанной цепочке любого из этих правил, будет непосредственно выводима из нее. Вовторых, если уже фиксировано правило вывода, применимое к цепочке γ, то существуют, вообще говоря, несколько различных вхождений левой части этого правила в цепочку γ. Тогда любая цепочка, полученная заменой любого из этих вхождений правой частью выбранного правила вывода, будет непосредственно выводима из γ. Для грамматики примера 7.3, правила аВ → Ва и цепочки γ = bаВаВа получим: bаВаВа ⊢ bВааВа и bаВаВа ⊢ bаВВаа.

Разные вхождения левой части некоторого правила в заданную цепочку могут и пересекаться. Так, правило аВа→ bВb грамматики примера 7.3 можно к написанному выше слову γ применить двояко: bаВаВа ⊢ bbВЬВа и bаВаВа ⊢ bаВbВb.

Заметим, наконец, что множество цепочек, непосредственно выводимых из данной, пусто тог да и только тогда, когда среди правил вывода грамматики нет ни одного, применимого к данной цепочке. Для примера 7.3 в качестве такой цепочки можно взять хотя бы цепочку аВА.

Определение 7.7.Выводом в грамматике G называют произвольную, конечную или бесконечную, последовательность слов α0 , α1 ,..., αn, ... , в которой для любого i ≥ 0 αi ⊢ αi+1, если цепочка αi+1 существует. Число n ≥ 0 называют длиной вывода, если указанная последовательность конечна и αn - ее последний элемент. В :этом случае говорят также, что αn выводится из α0 за n шагов. Для положительного n пишем α0+ αn или, если нужно специально оговорить длину вывода α0n αn.

Из определений следует, что выводимость γ ⊢* δ равносильна тому, что существует вывод γ = α01, ... ,αn = δ, где n ≥ 0.

Мы будем использовать также термин "фрагмент вывода", понимая под этим такую подпоследовательность вывода, которая сама является выводом. В частности, фрагмент вывода, состоящий из двух соседних его членов, называется шагом вывода.

Построение вывода в порождающей грамматике можно трактовать как "игру", правила которой заданы множеством Р. Подобно тому как в игре (например, в шахматах) можно из заданной позиции перейти в одну из множества следующих позиций, используя правила игры, так и при проведении вывода в грамматике можно из данной цепочки получить одну из множества непосредственно выводимых из нее, заменяя в ней произвольное вхождение левой части правила его правой частью. При этом мы можем выбрать любое правило, применимое к очередной цепочке, и среди различных вхождений его левой части выбрать любое.

На основании сказанного можно предположить, что существуют несколько различных выводов фиксированной цепочки β из фиксированной цепочки α. Далее на примерах мы убедимся в том, что это действительно так.

Введенные выше понятия непосредственной выводимости, выводимости и вывода можно уподобить известным из теории графов понятиям непосредственной достижимости, достижимости и пути (в ориентированных графах) соответственно. Мы специально выбирали обозначения выводимости близкими к тем, которые используют в теории графов. Нужно только заметить, что множество вершин графа конечно (по крайней мере, мы в этой книге изучаем только конечные графы), а множество слов бесконечно. Но графовая аналогия позволяет придать введеным выше понятиям большую наглядность: так, построение вывода в грамматике можно уподобить "путешествию" по некоторому пути в ориентированном графе.

Центральным понятием в теории порождающих грамматик является понятие языка, порождаемого данной грамматикой.

Определение 7.8. Язык, порождаемый грамматикой G, - это множество L(G) всех выводимых из аксиомы грамматики терминальных цепочек:

L(G) = {х: S*G х,х ∈ V*}.

Продолжая "игровую аналогию", мы можем теперь сказать, что у "игры", во-первых, появилась выделенная "начальная позиция", аксиома; во-вторых, возникла "цель" - строя вывод в согласии с правилами грамматики, получить цепочку, не содержащую нетерминалов. Так, скажем, и в шахматах, мы начинаем игру не с произвольной позиции, а со вполне определенной начальной позиции, предусматривающей строго фиксированную расстановку фигур, а закончить игру стремимся в любой позиции, в которой вражескому королю поставлен мат. Но при этом нужно понимать, что правила вывода грамматики априори никак не связаны с ограничением строить выводы терминальных цепочек из аксиомы, а определяют возможность построения любого вывода, даже бесконечного.

Заметим также, что, согласно определению 7.8, нетерминалы не содержатся в цепочках языка, порождаемого грамматикой. Это совсем не значит, что нетерминалы "не нужны", напротив, с их помощью мы организуем вывод и можем получить требуемые терминальные цепочки. Когда мы решаем математическую расчетную задачу и должны в результате получить число, то это не значит, что мы не должны пользоваться формулами. Но все буквенные обозначения в окончательном результате должны исчезнуть, хотя без них этот результат получить невозможно.

Определение 7.9. Две грамматики называются эквивалентными, если они порождают один и тот же язык.

Примем оглашение о следующей сокращенной записи правил с одинаковой левой частью: вместо записи

A → α1, A → α2, ..., A → αn,

будем использовать запись

A → α12|...|αn ,

разделяя разные правые части вертикальной чертой.

Кроме того, рассматривая примеры грамматик, мы зачастую будем записывать только их множества правил вывода, избегая скрупулезной записи всего ко ртежа, определяющего грамматику. С учетом введенных вьппе соглашений об обозначениях это не должно приводить к недоразумениям.

Пример 7.4. Рассматриваемая ниже грамматика моделирует простейший фрагмент естественного (русского) языка: ее терминалы - это некоторые слова русского языка*, нетерминалами являются "грамматические категории", а именно понятия "предложение", "подлежащее" и "сказуемое" (они даны как слова, заключенные в угловые скобки):

G1 = ({ кот, пес, крокодил, мяукает, лает, плачет},

{〈предложение〉, 〈подлежащее〉, 〈сказуемое〉},

〈предложение〉, P1).

Множество правил P1 имеет вид

〈предложение〉 → 〈подлежащее〉〈сказуемое〉,

〈предложение〉 → кот | пес | крокодил,

〈сказуемое〉 → мяукает | лает | плачет.

Каждое правило вывода грамматики G1 можно трактовать как определение той или иной грамматической категории: например, первое правило есть запись такого определения: "предложение - это подлежащее, за которым идет сказуемое". Так как нас интересует только синтаксис языка, то это определение, касающееся исключительно записи предложения, есть требование, согласно которому, записывая предложение, сначала нужно поставить подлежащее, а после него - сказуемое. Другие правила грамматики определяют подобным образом "подлежащее" и "сказуемое". Но тут новых грамматических категорий не возникает - просто перечисляются те слова, которые могут быть подлежащим и сказуемым.

* Эти слова рассматриваются как неделимые символы, а именно буквы данного терминального алфавита. Нас никак не должно это смущать, ибо алфавит - это любое непустое конечное множество.

Построим какой-нибудь вывод в грамматике G1:

〈предложение〉 ⊢ 〈подлежащее〉 〈сказуемое〉 ⊢ кот 〈сказуемое〉 ⊢ кот лает.

Заметим, что "смысл" (семантика) выводимой цепочки нас никак не интересует. Мы вообще пока не знаем, что такое "смысл". Так что кот может лаять, крокодил мяукать и т.д. #

Приведенный пример, несмотря на его простоту, позволяет нам дать еще одну содержательную интерпретацию понятия грамматики. Грамматику можно рассматривать как "систему определений" некоторых "терминов", "понятий". Выделяется самое общее понятие (в данном примере понятие "предложение"), оно сводится к менее общим "понятиям" до тех пор, пока мы не придем к "конкретным объектам" (в данном случае к цепочкам в каком-то алфавите), подпадающим под определяемые "понятия". Самое общее "понятие" - это аксиома, другие "понятия" - нетерминалы, "конкретные объекты" - терминальные цепочки. В подобном духе строится определение синтаксиса языков программирования с помощью так называемых форм Бэкуса - Наура. Пример такого описания приведен ниже. За другими примерами следует также обратиться к литературе по языкам программирования.

Пример 7.5. а. Грамматика

G2 = ({а,b,0,1}, {I,D}, I, Р2)

имеет множество правил Р2:

I → aD|bD|a|b,

D → aD|bD|0D|1D|a|b|0|1.

Нетрудно видеть, что данная грамматика порождает простейшие "идентификаторы" в алфавите, состоящем из двух "букв" и двух "цифр", т.е. цепочки, начинающиеся обязательно с "буквы".

Примеры выводов в грамматике G2:

I ⊢ aD ⊢ abD ⊢ ab0D ⊢ ab0bD ⊢ ab0b1,

I ⊢ a, I ⊢ b.

б. Грамматика

G3 = 〈{(, )}, {S}, S, S → () |(S) | SS〉

порождает множество так называемых" правильных скобочных структур"*, например S ⊢ SS ⊢ (S)S ⊢ (())S ⊢ (())().

Полезно сопоставить с этой грамматикой индуктивное определение множества правильных скобочных структур: цепочка () есть правильная скобочная структура; если известно, что цепочки х и у - правильные скобочные структуры, то цепочку ху также считаем правильной скобочной структурой; если известно, что х - правильная скобочная структура, то и цепочка (х) есть правильная скобочная структура; никаких правильных скобочных структур, кроме определенных выше, не существует. Видно, что грамматика G3 есть не что иное, как форма записи сформулированного только что индуктивного определения: "правильная скобочная структура" (понятие, обозначенное аксиомой S) есть либо цепочка (), либо "правильная скобочная структура" в скобках - (S), либо две "правильиые с кобочные структуры", записаияые одна после другой, - SS.

* Мы заключили четверку, эадающую грамматику G3, в угловые, а не в круглые скобки, чтобы не смешивать их со скобками, являющимися терминалами данной грамматики.

в. Рассмотрим грамматику

G3 = ({а, b, с}, {S, А, В, С}, S, Р4)

с множеством правил вывода Р4:

S → aSBC|abC, (1)|(2)

CB → BC, (3)

bB → bb, (4)

bC → bc, (5)

cC → cc. (6)

Разберем некоторые примеры выводов: под символом ⊢ будем указывать номер применяемого на данном шаге правила, а над символом - количество повторений этого правила:

S ⊢2 аbС ⊢5 аbс;

S ⊢1 aSBC ⊢2 ааbСВС ⊢3 ааbВСС ⊢4

4 ааbbСС ⊢5 ааbbсС ⊢6 ааbbсс;

S⊢1 aSBC⊢1 aaSBCBC⊢2 аааbСВСВС ⊢3

3 аааbВССВС ⊢3 аааbВСВСС ⊢3 аааbВВССС ⊢4

4 аааbbВССС ⊢4 аааbbbССС ⊢5 аааbbbсСС ⊢26 аааbbbссс.

Представим теперь вывод произвольной цепочки anbncn:

S⊢1 aSBC⊢1 aaSBCBC⊢1 ... ⊢1 anS(BC)n-12

...⊢3 anbBn-1Cn4 anbbBn-2Cn4...

...⊢4 anbnCn5 anbncCn-1n-16anbncn. (7.2)

Можно заметить, что посредством многократного применения правила (3) в выводе (7.2) происходит "перегонка" всех букв В влево от всех букв С, т.е. из цепочки

выводится цепочка anbBn-1Cn. Если считать, что правило (3) на каждом шаге соответствующего вывода применяется так, что происходит замена первого вхождения цепочки С В цепочкой ВС, то первый (самый левый) символ В в цепочке

"проходит" через один символ с, следующему символу В

нужно пройти уже два символа С и т.д. Отсюда следует, что правило (3) в указанном фрагменте вывода (7.2) применяется

Тогда последовательность номеров применяемых правил (протокол вывода) может быть записана так:

Гораздо труднее доказать, что данная грамматика порождает только цепочки указанного вида. Проанализируем другие варианты проведения вывода после применения правила (2) в выводе (7.2).

1. После применения правила (2) применяем правило (5) и после многократного применения правила (3) получаем

anbC(BC)n-15 anbc(BC)n-1 =

= anbcBC BC ... ВС⊢+3an bcBn-1Cn-1.     (7.3)

Цепочка, записанная последней, такова, что, во-первых, она не является терминальной, а во-вторых, к ней не применимо ни одно правило грамматики. Любая такая цепочка называется тупиковой.

2. Вывод (7.2) можно модифицировать, прервав на определенном шаге применение правила (3) и применив правило (4):

anbBmCm+1(BC)n-1-n = = anbBmCm+1BC...BC ⊢4anbbBm-1Cm+1(BC)n-1-m, где m < n-1.

Далее, если посредством применения правила (3) мы "перегоним" все символы В влево, то получим цепочку аnbbBn-2Cn, из которой легко получается цепочка anbncn. Таким образом, мы получили другой вариант вывода этой цепочки.

Но если мы будем применять правило (4), начиная с цепочки

до тех пор, пока это возможно, то получим цепочку

Из нее, если не применять сразу правило (5), снова получится цепочка anbncn. Применение же правила (5) приведет к тупиковой цепочке.

По аналогии можно рассмотреть произвольное чередование применения правил (3) и (4).

Все варианты вывода терминальной цепочки тем самым разобраны.

В общем же случае строгое доказательство того, что какаялибо предъявленная нам грамматика не порождает никаких других цепочек, кроме цепочек определенного вида, может быть весьма нетривиальным.

г. Зададим грамматику

G5=({a}, {S,A,C,D,E,F}, S, P5),

множеством P5 правил

S → aCA,

A → a2EA|F,

EF → DF,

ED → Da2 E,

Еа → аЕ,

Са → аС,

CD → Ca,

СF → λ.

Можно доказать, что данная грамматика порождает язык {an2: n ≥ 1}, т.е. все квадраты натуральных чисел, закодированных в однобуквенном алфавите. #

При доказательстве утверждений о грамматиках нам будет удобно использовать одну процедуру, которую мы назовем переименованием нетерминалов грамматики.

Пусть дана какая-то грамматика G = (V, N, S, Р). Введем новый алфавит N', не пересекающийся с V ∪ N, так, что между алфавитами N и N' установлено взаимно однозначное соответствие, при котором каждый символ А ∈ N переходит в символ А' ∈ N'. Построим новую грамматику G' = (V, N', S', Р'), заменив каждое правило в исходной грамматике новым, в котором на месте каждого вхождения каждого нетермииала А ∈ N поставлен нетерминал А' ∈ N'. Нетрудно доказать, что построенная таким образом грамматика G' эквивалентна исходной. Говоря неформально, описанное преобразование грамматики состоит в переобозначении ее нетерминалов таким образом, что вместо каждого нетерминала ставится его "двойник", причем "двойники", соответствующие разным нетерминалам, различны.