Опубликован: 23.10.2009 | Уровень: для всех | Доступ: платный
Лекция 10:

Описание формальных грамматик

< Лекция 9 || Лекция 10: 123 || Лекция 11 >
Аннотация: В данном разделе рассматриваются основы дисциплины: "формальная грамматика". Эта дисциплина рассматривает любые операции с символами, а ее выводы широко используются при анализе формальных и "человеческих" языков, а также в искусственном интеллекте. Эта лекция является самой важной и, одновременно, самой сложной для понимания лекцией курса. В связи с этим автор преподносит читателю только ее выводы, опуская математические доказательства. Для лучшего понимания материала может потребоваться обращение к материалам предыдущих и последующих лекций.

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

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

Выводы теории формальных грамматик используются в языках логического программирования (например, ПРОЛОГ) для построения деревьев вывода.

При чтении этого раздела Вам может быть потребуется обращаться как к предыдущим, так и последующим разделам. Более подробно материал из этого раздела представлен в [41].

10.1. Алфавит

Изучение любого языка человек начинает с азбуки. В формальной грамматике язык определяется вне зависимости от его смысла. Более того, один и тот же язык может формироваться несколькими грамматиками! Это как в школе - не так важен результат (который можно прочитать в конце учебника), как его получение - зафиксированное в тетради решение задачи. Поэтому подойдем к определению алфавита также формально.

О п р е д е л е н и е. Алфавит - это непустое конечное множество элементов.

В "классическом" языке алфавит - это набор литер. В фонетике - набор издаваемых человеком звуков речи. В музыке - это набор нот, и т.д.

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

Всякая конечная последовательность символов алфавита называется словом, или, более профессионально, цепочкой. Цепочками, состоящими из символов {a, b, c}, будут следующие последовательности: a, b, c, aa, ab, bc, ac, bb, abba и другие. Также допускается существование пустой цепочки Л - полное отсутствие символов. Важен также порядок следования символов в цепочке. Так, цепочки ab и ba - разные цепочки. Далее заглавные латинские буквы будут использованы как переменные и символы, а строчные латинские буквы будут обозначать цепочки. Например:

x = SVT
Листинг 10.1.

цепочка, состоящая из символов S, V и T, и именно в этом порядке.

О п р е д е л е н и е. Длиной цепочки называется число символов в этой цепочке. Она обозначается как |x|. Например: |Л| = 0, |A| = 1, |BA| = 2, |ABBA| = 4.

Если x и y являются цепочками, то их конкатенацией будет цепочка xy. От перестановки цепочек при конкатенации результат меняется (как и в теории групп). Если z = xy - цепочка, то x - голова, а y - хвост цепочки. Если нам безразлична голова цепочки, мы будем обозначать:

z = … x
Листинг 10.2.

а если нам безразличен хвост, мы будем писать:

z = x …
Листинг 10.3.

О п р е де л е н и е. Произведение двух множеств цепочек определяется как конкатенация всех цепочек, входящих в эти множества. Например, если множество A = {a, b}, а B = {c,d}, то:

AB = {ac, ad, bc, bd}
Листинг 10.4.

В произведении множеств, как и при конкатенации, порядок множителей существенен.

И при конкатенации цепочек, и при перемножении множеств цепочек истинным остается ассоциативный закон, записывающийся как:

z = (ab)c = a(bc) = abc
Листинг 10.5.
D = (AB)C = A(BC) = ABC
Листинг 10.6.

И, наконец, определим степень цепочки. Если x - непустая цепочка, то x0 = {Л}, x1 = x, x2 = xx, xn = x(x)(n-1). То же самое обстоит и со степенью множеств.

10.2. Терминальные и нетерминальные символы

Понятие терминальных и нетерминальных символов тесно связано с понятием правила подстановки (или продукции). Дадим его определение.

О п р е д е л е н и е. Продукцией, или правилом подстановки, называется упорядоченная пара ( U, x ), записываемая как:

U ::= x
Листинг 10.7.

где U - символ, а x - непустая конечная цепочка символов.

Символы, встречающиеся только в правой части, называются терминальными символами. Символы, встречающиеся и в левой, и в правой части правил, называются нетерминальными символами, или синтаксическими единицами языка. Множество нетерминальных символов обозначается как VN, а терминальных символов - VT.

Примечание. Данное определение терминальных и нетерминальных символов истинно для КС-грамматик и A-грамматик (см. раздел 10.4.3).

О п р е д е л е н и е. Грамматикой G[Z] называют конечное, непустое множество правил, содержащее нетерминальный символ Z хотя бы один раз на множестве правил. Символ Z называют начальным символом. Далее мы все нетерминальные символы будем обозначать как <символ>.

[Пример 01]

Грамматика: "число"

<число> ::= <чс>
<чс> ::= <цифра>
<чс> ::= <чс><цифра>
<цифра> ::= 0
<цифра> ::= 1
<цифра> ::= 2
<цифра> ::= 3
<цифра> ::= 4
<цифра> ::= 5
<цифра> ::= 6
<цифра> ::= 7
<цифра> ::= 8
<цифра> ::= 9

Дадим еще определение:

О п р е д е л е н и е. Цепочка v непосредственно порождает цепочку w, если:

v = x<U>y, а w = xuy
Листинг 10.8.

где <U> ::= u - правило грамматики. Это обозначается как v => w. Мы также говорим, что цепочка w непосредственно выводима из v. При этом цепочки x и y могут быть пустыми.

О п р е д е л е н и е. Говорят, что v порождает w, или w приводится к v, если существует конечная цепочка выводов u0, u1, …, u[n] (n > 0), такая, что

v = u0 => u1 => u2 => … => u[n] = w
Листинг 10.9.

Эта последовательность называется выводом длиной n, и обозначается v =>+ w. И, наконец, пишут:

v =>* w, если v => w или v =>+ w
Листинг 10.10.

10.3. Фразы

О п р е д е л е н и е. Пусть G[Z] - грамматика, x - цепочка. Тогда x называют сентенциальной формой, если <Z> =>* x. Предложение - это сентенциальная форма, состоящая только из терминальных символов. Язык - это подмножество множеств всех терминальных цепочек.

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

О п р е д е л е н и е. Пусть G[Z] - грамматика. И пусть w = xuy - сентенциальная форма. Тогда u называется фразой сентенциальной формы w для нетерминального символа <U>, если:

Z =>* x<U>y и <U> =>+ u
Листинг 10.11.

Если же

Z =>* x<U>y и <U> => u
Листинг 10.12.

то цепочка u называется простой фразой.

Следует быть осторожным с термином "фраза". Тот факт, что <U> =>+ u (цепочка u выводима из <U> ) вовсе не означает, что u является фразой сентенциальной формы x<U>y; необходима также выводимость цепочки x<U>y из начального символа грамматики Z.

В качестве иллюстрации фразы рассмотрим [Пример 01] сентенциальную форму <чс>1. Значит ли это, что символ <чс> является фразой, если существует правило: <число> ::= <чс>? Конечно же, нет, поскольку невозможен вывод цепочки: <число><1> - из начального символа: <число>. Какие же фразы сентенциальной формы <чс>1? Рассмотрим вывод:

<число> => <чс> => <чс><цифра> => <чс><1>
Листинг 10.13.

Таким образом,

<число> =>* <чс> и <чс> =>+ <чс>1
Листинг 10.14.
<число>  => <чс><цифра> и <цифра> => 1
Листинг 10.15.

Следовательно, <чс>1 и 1 - фразы. Простой же фразой будет только 1.

О п р е д е л е н и е. Основой всякой сентенциальной формы является ее самая левая простая фраза.

Грамматика из [примера 01] описывает бесконечный язык, то есть содержащий в себе бесконечное число предложений. Это объясняется тем, что грамматика содержит правило: <чс> ::= <чс><цифра>, то есть в некотором смысле символ <чс> сам себя определяет.

В общем случае, если:

<U> =>+ … <U> …
Листинг 10.16.

мы говорим, что грамматика рекурсивна относительно символа <U>. Если же:

<U> =>+ <U> …
Листинг 10.17.

то имеет место левая рекурсия, а если

<U> =>+ … <U>
Листинг 10.18.

то имеет место правая рекурсия.

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

Замечание о левосторонней рекурсии. Некоторые алгоритмы, реализующие обратный вывод, могут при левосторонней рекурсии попасть в "бесконечный цикл". Например, в грамматики из [примера 01] третье правило может выполняться бесконечно: при обращении к правилу: <чс> ::= <чс><цифра> - программа будет "обращать внимание" на символ <чс> и "не замечать" символа <цифра>. Это можно исправить как подбором грамматики, так подбором порядка расположения правил и фактов. Например, в языке ПРОЛОГ вначале пишется правило, вызывающее остановку рекурсии, а уже потом - собственно рекурсивное правило.
Замечание. Тут имеется некоторая "нестыковка" с утверждением из [пункта 3 "Грамматика" ], которое утверждает, что результат вывода не зависит от порядка правил. Однако решение задачи (результат алгоритма) действительно не зависит от порядка правил - от него зависит лишь то, будет ли выдано решение при конечном числе шагов, завершится ли программа нормально или даст сбой системы. Это - не недостаток грамматики, а недостаток алгоритма, ее порождающего.

Отступление. Вообще, чем больше в грамматике рекурсивных правил, тем сложней и богаче язык и тем более сложные конструкции можно на нем описать. Это относится не только к языкам программирования, но и к "человеческим" языкам. Так, в одном из номеров журнала "Компьютерра" за 2007 год приводилась статья о языке одного бразильского индейского племени. В его языке почти отсутствовала рекурсия, характерная для большинства языков Европы и Азии. Это мешало индейцам из этого племени, например, воспринять Библию. Это позволило автору статьи сделать вывод, что чем более в языке народа рекурсии, тем более "прогрессивнее" и "цивилизованнее" народ. Автор статьи утверждает, что это пока лишь гипотеза, еще требующая подтверждения. Но эти выводы все равно подтверждают важность рекурсии при выборе грамматики.

< Лекция 9 || Лекция 10: 123 || Лекция 11 >
Юрий Фролов
Юрий Фролов
Украина
Ольга Галанина
Ольга Галанина
Россия