- •Введение
- •1. Грамматики, автоматы и контекстно-свободные языки
- •If выражение then if выражение then другой_оператор else другой_оператор
- •2. Грамматики, машины тьюринга и перечислимые языки
- •3. Теория алгоритмов и рекурсивных функций
- •4. Теория сложности
- •Мы определяем ее через
- •5. Упражнения
- •Рекомендуемая литература
- •Содержание
If выражение then if выражение then другой_оператор else другой_оператор
имеет два различных дерева вывода. Необходимая для языка программирования однозначность грамматики достигается тем, что вышеуказанная программа ставится в соответствие всегда только одному из двух возможных деревьев вывода. □
Контекстно-свободные грамматики, продукции которых имеют простую структуру, называются регулярными грамматиками. Контекстно-свободная грамматика G = (Ф, , P, S) называется регулярной, если все продукции имеют вид: А аВ‚ А а‚ или S ε‚ А‚ ВΦ‚ а. Однако продукция S ε может встречаться только тогда, когда S не встречается нигде в правой части продукции. Таким образом, продукции вида А aS запрещены.
Формальный язык L называется регулярным, если существует регулярная грамматика G, такая что L(G) = L. Отсюда сразу следует, что каждый регулярный язык также контекстно-свободный. Однако обратное неверно: именно {anbn | n1} контекстно-свободный, но не регулярный язык. Позже мы увидим, что множество всех констант в PASCAL – регулярный язык (см. пример 1.11).
Пример 1.5. Контекстно-свободная грамматика.
G = ({E,T}, {+,,a}, P, E), где P = {EΕ+T, ET, TTa, Ta}
порождает язык L(G) = a(a)(+a(a)). Поэтому возможны следующие продукции:
Е T+T+...+T, T aa...a.
Слова из L(G) могут рассматриваться как арифметические выражения без скобок. Однако возможно указать некоторую регулярную грамматику G’, которая порождает L(G), именно: G’ = ({S,A}, {+,,a}, P’, S), где P’ = {SаА‚ Sа‚ А+S, AS}. Тогда L(G) регулярный язык. □
Разберем теперь проблему анализа некоторого заданного слова w относительно грамматики G. Под этим понимается следующее.
Пусть G = (Ф, , P, S) и w. Тогда требуется проверить, является ли w словом из L(G). Эта проблема встречается при трансляции программ. В случае, если L(G) – множество всех синтаксически правильных программ и w – программа, то требуется проверить, является ли w синтаксически правильной программой, то есть лежит ли w в L(G). Мы увидим, что конечные автоматы (соответственно, магазинные автоматы) могут применяться для разрешения проблемы анализа в отношении регулярных (соответственно, контекстно-свободных грамматик).
Конечный автомат обладает конечным числом состояний и входной лентой со считывающей головкой. Если конечный автомат находится в некотором состоянии и считывающая головка читает символ на входной ленте, то функция перехода недетерминировано в зависимости от предыдущего состояния и прочитанного символа определяет новое состояние и считывающая головка смещается на один символ вправо. Конечный автомат имеет, кроме того, одно начальное состояние и сколь угодно много конечных состояний. Некоторое слово воспринимается конечным автоматом тогда и только тогда, когда это слово как содержимое входной ленты переводит конечный автомат из начального состояния в некоторое конечное состояние. В общем случае конечный автомат работает недетерминировано. Существует несколько возможных определений конечных автоматов.
Конечный автомат A над алфавитом есть система A =(Q, , , q0, F),
-
Q
где:
– конечное непустое множество состояний; -
– входной алфавит;
-
: Q P(Q) (степень множества Q) – функция перехода;
-
q0Q – начальное состояние;
-
F Q – множество конечных состояний.
Продолжим отображение до отображения : Q P(Q) путем
(q, ) = {q}, (q, aw) = для каждого qQ, w, a.
Слово w принимается конечным автоматом A тогда и только тогда, когда F (q0, w) . Формальный язык ||A||, принимаемый автоматом A, есть ||A|| = {w | F (q0, w) }.
В случае, если не возникает путаницы, вместо пишут просто .
Функцию перехода можно также представить так называемой таблицей переходов.
Пусть A = (Q, , , q0, F), где Q = {q0, q1, …, qn} и = {a1, a2, …, am}, тогда изображается следующей таблицей:
|
a1 |
a2 |
… |
am |
q0 |
(q0, a1) |
(q0, a2) |
… |
(q0, am) |
q1 |
(q1, a1) |
(q1, a2) |
… |
(q1, am) |
. |
. |
. |
|
. |
. |
. |
. |
|
. |
. |
. |
. |
|
. |
qn |
(qn, a1) |
(qn, a2) |
… |
(qn, am) |
Другая возможность – представление функции перехода ориентированным помеченным графом. Граф имеет n+1 узлов, которые соответствуют состояниям q0,…, qn. Если выполняется q(p, a), то ребро, обозначенное символом а, ведет от узла p к узлу q. Узел, соответствующий начальному состоянию, обозначается зачерненным, а узлы, соответствующие конечным состояниям, заключаются в кольцо.
Слово a1…am описывает путь от p к q в графе, в случае если существуют узлы p1 = p,p2,…,pm,pm+1 = q, так, что для каждого j, 1jm, имеется ребро от pj к pj+1, которое обозначается как aj. Пустое слово описывает для любого q путь от q к q. Поэтому справедливо, что слово w в точности тогда описывает путь в графе от p к q, когда q(p,w). Отсюда ||A|| – множество всех слов, которые описывают путь от начального состояния к одному из конечных состояний.
Пусть G = (Ф, , P, S) – регулярная грамматика. Построим граф конечного автомата, который воспринимает L(G).
Множество узлов графа задается как Ф {F}. Узел F – конечный узел.
Если S , то S также конечный узел. Начальный узел задается через S.
Если A a, то ребро, обозначенное через а, ведет от узла А к конечному узлу F.
Если A aB, то ребро а ведет от узла А к узлу В.
Пример 1.5. (продолжение). Построим граф конечного автомата, воспринимающего L(G):
Конечный автомат A = (Q, , , q0, F) – детерминированный, если |(q, x)|1 для всех qQ, x. Вместо (q, x) = {p} пишем тогда (q, x) = p, что означает, что мы рассматриваем как частичную функцию : Q Q. Определение для упрощается тогда до следующего:
(q, ε) = q, (q, aw) =((q, a), w) и ||A|| = {w | (q0, w)F}.
На графе это означает, что от каждого узла q отходит не более чем одно ребро, обозначаемое х.
Справедлива следующая теорема:
Пусть A = (Q, , , q0, F) – конечный автомат, тогда имеется детерминированный конечный автомат A’, такой что ||A|| = ||A’||.
Мы хотим теперь построить автомат A’ с множеством состояний P(Q). Продолжим : Q P(Q) до отображения ’: P(Q) P(Q) посредством
′({q1, q2,..., qk}, x) =(qj, x), q1,..., qkQ, x.
Таким образом, ’({q1, q2,..., qk}, x) есть множество всех тех состояний, которые могут быть достигнуты из одного из состояний q1, q2,..., qk через ребро, обозначенное x. Пусть F’ = {GP(Q) | GF≠ Ø}, что значит множество G как состояние автомата A’ есть конечное состояние тогда и только тогда, когда оно содержит хотя бы одно конечное состояние из F. Пусть A’ = (P(Q), , ’, {q0}, F’). Тогда выполняется ||A’|| = ||A|| и A’ по построению – детерминированный автомат.
Пример 1.5. (продолжение). Построим граф детерминированного конечного автомата, который принимает L(G):
С помощью детерминированных конечных автоматов можно конечно «быстро» анализировать регулярные языки. Обратно: можно показать, что для каждого конечного автомата A найдется регулярная грамматика G, такая что L(G) = ||A||.
Предложение 1.1. Пусть L – формальный язык. Тогда следующие высказывания эквивалентны:
-
существует регулярная грамматика G, такая что L = L(G);
-
существует конечный автомат A, такой что L = ||A||;
-
существует детерминированный конечный автомат, такой что L = ||A||. □
Пример 1.6. Слово v называется подсловом слова w тогда и только тогда, когда найдутся слова u1,u2, такие, что w = u1 v u2. Требуется проверить, встречаются ли в слове w подслова с определенными свойствами. Для этого строят детерминированный конечный автомат A, который принимает все слова w, содержащие подслова с определенными свойствами. Это есть простейшая проблема распознавания образов («сопоставление с образцом»).
Пусть = {a, b}. Требуется проверить, обладает ли слово w следующими свойствами:
-
ааа должно быть подсловом слова w;
-
аa должно встречаться как подслово на правом конце слова w.
Таким образом, можно построить детерминированный конечный автомат, который принимает формальный язык L={a,b}ааа{a,b}{a,b}аа. Укажем две возможных конструкции.
Первый способ построения: конечный автомат вида
принимает L. Чтобы его «детерминировать» представим функцию перехода в виде таблицы (без фигурных скобок) и определим функцию перехода детерминированного автомата.
|
a |
b |
q0 |
q0, q1 |
q0 |
q1 |
q2 |
– |
q2 |
q3 |
– |
q3 |
– |
q4 |
q4 |
q4, q5, |
q4 |
q5 |
q6 |
– |
q6 |
– |
– |
q0, q1 |
q0, q1, q2 |
q0 |
q0, q1, q2 |
q0, q1, q2, q3 |
q0 |
q0, q1, q2, q3 |
q0, q1, q2, q3 |
q0, q4 |
q0, q4 |
q0, q1, q4, q5 |
q0, q4 |
q0, q1, q4, q5 |
q0, q1, q2, q4,q5, q6 |
q0, q4 |
q0, q1, q2, q4, q5, q6 |
q0, q1, q2, q3,q4,q5,q6 |
q0, q4 |
q0, q1, q2, q3, q4, q5, q6 |
q0, q1, q2, q3, q4, q5, q6 |
q0, q4 |
Это дает следующий детерминированный конечный автомат:
Относительно состояний p3, p6, p7 видно следующее: три состояния являются конечными состояниями. Символ a переводит автомат из одного из этих трех состояний снова в одно из трех состояний; символ b переводит из всех трех состояний в состояние p4. Поэтому можно три состояния p3, p6, p7 объединить в одно состояние p, при этом получают следующий детерминированный автомат:
Второй способ построения. Видно, что слово лежит в L тогда и только тогда, когда оно заканчивается на aaa или содержит aaa и заканчивается на aa:
Затем дополняют этот «скелет автомата» до вышеописанного автомата.
Обратимся к магазинным автоматам.
Магазин – это накопитель, в котором может читаться или изменяться только самый верхний символ.
Магазинный автомат имеет конечное число состояний, входную ленту со считывающей головкой и магазинную ленту (стек) с головкой чтения-записи, которая находится над самым верхним магазинным символом. Если магазинный автомат находится в некотором состоянии, читающая головка читает символ с входной ленты и головка чтения-записи читает самый верхний символ на магазинной ленте, то функция перехода определяет недетерминированным образом, в зависимости от старого состояния и двух прочитанных символов, следующие действия:
1) читающая головка остается над прочитанным символом или передвигается на один символ вправо;
2) самый верхний символ в магазине стирается;
3) слово над алфавитом магазина записывается на магазинной ленте, и головка чтения-записи устанавливается на новый самый верхний символ магазинной ленты;
4) магазинный автомат переходит в новое состояние.
Итак, пусть дан магазинный автомат, работающий с входным алфавитом . На входной ленте пусть записано слово w*. Магазинный автомат стартует в заданном начальном состоянии, имеет читающую головку над первым символом входного слова и головку чтения-записи над стартовым символом в остальной части пустой магазинной ленты. Далее, автомат действует согласно пунктам 1) – 4). Если магазинному автомату удается попасть в так называемое конечное состояние, причем читающая головка должна стоять справа от последнего символа входной ленты, то тогда говорят, что магазинный автомат принимает w через конечное состояние. Если магазинному автомату удается достичь того, что магазинная лента пуста и читающая головка находится справа от последнего символа входной ленты, то говорят, что магазинный автомат принимает w через пустой магазин.
Формализуем теперь магазинные автоматы.
Магазинный автомат P есть семерка P = (Q, q0, p0, F), где
-
Q – непустое конечное множество состояний;
-
– алфавит, называемый входным алфавитом;
-
– алфавит, называемый алфавитом магазина;
-
q0Q – начальное состояние;
-
p0 – начальный символ на магазинной ленте;
-
FQ – множество конечных состояний;
-
Q PfQ Г* – функция перехода. (Через Pf мы обозначаем множество всех конечных подмножеств.)
Содержимое магазинной ленты есть слово, причем самый верхний символ магазина стоит крайним слева.
Интерпретация следующая:
Пусть (q,a,p)= (q1, 1),…,(qm, m) , q,q1,…,qm Q, a , p , 1, …, mГ*.
Если магазинный автомат находится в состоянии q, головка чтения читает символ a, а головка чтения-записи читает самый верхний символ в магазине p, то магазинный автомат выбирает недетерминированным образом некоторую пару (qi, i). Это означает, что магазинный автомат переходит в состояние qi, на магазинной ленте p замещается на i, головка чтения передвигается на один символ вправо и головка чтения-записи устанавливается над самым верхним (первым) символом слова i.
Если выполняется q, p (q1, 1),…,(qm, m) , то это означает, что головка чтения ничего не читает, а поэтому также и не перемещается вправо. Состояние и содержимое магазина изменяются, как описано выше.
Пусть P = (Q, , , , q0, p0, F) – магазинный автомат. Конфигурация (ситуация) магазинного автомата P есть тройка (q, w, ), qQ, w*, Г*. Интуитивно это означает, что автомат находится в состоянии q, что слово w – еще не прочитанная часть входного слова и что стоит на магазинной ленте.
Определим далее отношение P, называемое прямым отношением перехода над конфигурациями P:
(q1, aw, p) P (q2, w, 1) (q2, 1)(q1, a, p) для q1, q2 Q, a, w*, p, , 1 *
Отношение P* есть рефлексивное и транзитивное замыкание P. Если выполняется (q1, w1, 1) P* (q2, w2, 2), то говорят, что конфигурация (q1, w1, 1) ведет к (q2, w2, 2). В случае, если ясно, какой магазинный автомат имеется в виду, вместо P и P*можно писать и *.
Пусть P = (Q, , , , q0, p0, F) – магазинный автомат. Язык T(P), который принимается автоматом P через конечное состояние, есть
T(P)=w(q0, w, p0) * (q,, ), qF, *.
Язык N(P), который принимается автоматом P через пустой магазин, есть
N(P)=w(q0, w, p0 * (q, ,), qQ.
Язык , который принимается автоматом P через пустой магазин и конечное состояние, есть
= w q0, w, p0 * (q, ,), qF.
Конечный автомат P – детерминированный тогда и только тогда, когда для всех qQ, a, p выполнено:
-
q, a, p) 1;
-
если q, , p , то q, x, p для всех x.
Магазинный автомат P Q, , , , q0, p0, F может быть представлен бесконечным ориентированным помеченным графом: множество узлов графа задается как q) *, qQ. От узла (1, q1) к узлу (2, q2) ведет в точности одно ребро, обозначенное a, если
q1,a, 1 (q2, , 2) т. е., если 1= p, 2 3 и (q2, 3) (q1,a, p).
Тогда справедливо, что w* в точности тогда описывает путь от (1, q1) к (2, q2), когда q1,w, 1 * (q2, , 2).
Отсюда следует непосредственно, что T(P) есть множество всех тех слов, которые описывают путь от (p0,q0) к (, q), qF, *; что N(P) есть множество всех слов, описывающих путь от (p0,q0) к (, q), qQ и что есть множество всех тех слов, которые описывают путь от (p0,q0) к ( q), qF.
Пусть G=(S) – контекстно-свободная грамматика, тогда магазинный автомат P = (qVqSq принимает язык L(G) через пустой магазин (и конечное состояние), причем определена следующим образом:
(q, B) q, , A) A B P, B ,
(q, ) q, a, A) A a P, a ,
(q, ) q, , A) A P,
(q, x, x) = q, для всех x.
Пример 1.7. Для контекстно-свободной грамматики G = (SabSaSS, SbS получают P = ({q},,V,,q,S,{q}), где (q,,S)={(q,aSS),(q,b)}, (q,a,a)=(q,b,b)={(q,)}. Имеем: =N(P)=L(G). Автомат P – недетерминированный.
Конструкция будет проще, если контекстно-свободная грамматика G дана в нормальной форме Грайбах.
Контекстно-свободная грамматика G=(PS) дана в нормальной форме Грайбах, если
из AP следует или .
Можно показать, что для каждой контекстно-свободной грамматики G, где L(G) *, можно построить контекстно-свободную грамматику G1 в нормальной форме Грайбах, такую, что L(G1)=L(G).
Пусть G = (S) – контекстно-свободная грамматика в нормальной форме Грайбах. Тогда магазинный автомат P = ({q},,,,q,S,{q}) принимает язык L(G) через пустой магазин и конечное состояние, причем (q,)q,a,A AaP и (q,)(q,,A) A.
Пример 1.8. Пусть контекстно-свободная грамматика G = (S ab SaSS, SbS.
Тогда для P = ({q},,,,q,S,{q}), такого, что q,a,S={(q,SS)}, (q,b,S)={(q,)} выполняется: = N(P) = L(G). Магазинный автомат представляется следующим графом:
Он является детерминированным.
Можно доказать следующее предложение.
Предложение 1.2. Пусть L – формальный язык. Тогда следующие высказывания эквивалентны:
-
существует контекстно-свободная грамматика G, такая, что L = L(G);
-
существует магазинный автомат P, такой, что L=T(P);
-
существует магазинный автомат P, такой, что L=N(P);
-
существует магазинный автомат P, такой, что L=.
Существуют, однако, контекстно-свободные языки, которые не могут быть приняты никаким детерминированным магазинным автоматом. К их числу относится контекстно-свободный язык {wwR w0,1}*}, где R=, .
Если хотят анализировать некоторый контекстно-свободный язык, часто выгоднее строить магазинный автомат не через контекстно-свободную грамматику, а непосредственно.
Пример 1.9. Мы хотим построить магазинный автомат, который принимает все корректно записанные скобочные выражения со скобками x и .
Конструкция первая. Для G = ({S},{x,},{SxSS,S},S) и P = ({q},{x,}, {S,},,q,S,{q}), где q,x,S={(q,SS)}, (q,,S)={(q,)}, (q,,)={(q,)} выполняется, что L(G) есть множество корректно заданных скобочных выражений со скобками x и .
Конструкция вторая. Слово w над {x,} есть корректное скобочное выражение тогда и только тогда, когда
-
в каждом начальном подслове слова w число скобок не превосходит числа скобок x;
-
число скобок x и в w совпадают.
Отсюда получают магазинный автомат P = ({q},{x,},{ p0, p1},,q, p0,{q}), такой, что (q,x, p0) = {(q, p1p0)}, q,x, p1) = {(q, p1p1)}, q,, p1 = {(q,}, q,, p0 ={(q,)}.
Он представляется следующим графом (указаны только существенные узлы):
и является почти детерминированным (нужно только распознать конец).
В форме двух примеров укажем метод, с помощью которого из грамматики в нормальной форме Бэкуса можно построить магазинный автомат (и если повезет, то и даже конечный автомат), который пригоден для анализа. Метод применяет автоматы, соответствующие синтаксическим диаграммам языков Паскаль и Модула.
Пример 1.10. <F>(<F><O><F>)<vZ> <vZ><Z>{<Z>}
<O> <Z>:01
F,O,vZ и Z обозначают соответственно формулу, оператор, целое число без знака, цифру. Каждой переменной сопоставим синтаксическую диаграмму:
После замещения и в несколько измененной нотации мы получим:
vZ
Блок в синтаксической диаграмме для <F> мы не можем замещать непосредственно, так как конечный узел имеет петлю. Мы должны подставить:
и получим:
Если далее выполним постановку для F, получим магазинный автомат. При этом мы должны обозначить узлы через (,q), где q – состояние, – слово в магазине. Кроме того, нам потребуются два различных магазинных символа в зависимости от того, какое F мы замещаем.
Это дает магазинный автомат:
P ,
где
Магазинный автомат P производит анализ в основном детерминировано и акцептирует в точности все слова, порожденные с помощью <F>.
Пример 1.11. Подобным образом можно сконструировать следующий автомат для констант в Паскале.