12.02.2019
- годовой курс: зачёт+экзамен;
- Петрова Елена Александровна, elena.petrova@urfu.ru;
- консультации по понедельникам в 16:10 на кафедре алгебры и фундаментальной информатики.
- Языки, грамматики, распознаватели (Шур, Замятин) - основной учебник (много багов!)
- Ахо, Лам, Сети, Ульман "Компиляторы. Принципы, технологии, инструменты" (Dragon book)
- Ахо, Ульман "Теория синтаксического анализа, перевода и компиляции"
- Cooper K. Engineering a Compiler.
— Теорией компиляции. Узнаем:
- что такое язык;
- что такое компилятор;
- что делает компилятор с языком.
В итоге будем знать, как работают и как написать (в теории) компиляторы.
Немного комментариев и истории:
Даже разбор формулы в Экселе использует какие-то приёмы компиляции!
В 50-x годах людям надоело писать на ассемблере, и они начали думать. К 60-м придумали.
Дейкстра - двигатель прогресса, потому что придумал теорию, а не какое-то специфичное для задачи решение.
По-простому – переводчик с языка на язык. Можно рассматривать как чёрный ящик с каким-то входом, выходом и магией внутри.
Принято разделять его работу на 2 фазы:
фронтенд: анализ исходного текста. Если есть ошибки, то останавливаемся.
бэкенд: синтез - генерация программы, которая нам нужна вместе с какими-то оптимизациями.
Заниматься будем фронтендом!
лексический анализ: разбиваем текст на токены – знаки, переменные, идентификаторы.
синтаксический анализ (парсер): определяем, как можно получить такую терминальную строку
семантический анализ: проверка типов.
-
Лексика — слова
-
Синтаксис — правила построения предложений
-
Семантика — типы и подходящие им операции
Таблица символов - информация о переменных, константах, функциях. Используется на всех шагах анализа.
Заполнение:
-
лексика (?): встречаем новый символ - записываем имя переменной и указываем место первого появления.
-
семантика: тип, место хранения, время объявления
Написанию компилятора предшествует описание языка.
Рассмотрим язык с условным оператором. Что есть условный оператор с точки зрения синтаксиса? Опишем это с помощью форм Бэкуса–Наура1.
<условный оператор>::== if <логическое выражение> <список операторов> { else <список операторов> }
<список операторов>::== <оператор>|<оператор>;<список операторов>
...
<идентификатор>::== [a-zA-Z]\w*
Обозначения
| {} — альтернатива
<> — синтаксическая категория
::== — выводимость
[Порождающая] грамматика - объект математический. Основной способ описания синтаксиса и лексики (частный случай синтаксиса).
Опр. Грамматика
-
$\Sigma$ – терминальный алфавит (выходной); -
$\Gamma$ – нетерминальный алфавит (вспомогательный); -
$P$ – множество правил вывода; -
$S \in \Gamma$ – выделенный нетерминал – аксиома (одна).
Соглашения
-
$a, b, c, :…$ - терминальные символы (if - терминал); -
$x, y, z, :…$ - терминальные слова (последовательности терминальных символов); -
$A, B, C, :…$ - нетерминальные символы; -
$X, Y, Z, :…$ - слова из любых символов - то есть могут представлять как терминальный символ, так и нетерминальный символ; -
$\alpha, \beta, \gamma, :...$ - совокупные слова, содержащие как терминальные, так и нетерминальные символы. -
$\lambda$ - пустое слово.
Правило вывода:
Таким образом, терминальные символы стоит понимать как символы, из цепочек которых ничего нельзя вывести.
Основная функция этого правила — порождение языка.
Опр. Цепочка
$\sigma = \delta _1 \alpha \delta _2$ $\gamma = \delta_1\beta \delta _2$ $(\alpha \rightarrow \beta) \in P$
Обозначается как
В цепочке сигма есть подпоследовательность альфа, которую можно заменить бетой
Выводимость - отношение на множестве цепочек. Рефлексивно-транзитивное замыкание —$\sigma \Rightarrow^* \gamma$ — возможность вывести одну цепочку из другой за некоторое число шагов
Опр.
Последовательность
Получается, что грамматика для нас — просто набор правил вывода. Потому что всё остальное мы зафиксировали в обозначениях.
Опр. Язык, порождённый грамматикой
Опр. Дан вывод
$\eta_0=S$ $\eta_n=w$ $\eta _{i-1} \Rightarrow \eta _i$ -
$\eta_i$ — форма грамматики (шаг) — цепочка, принадлежащая выводу терминальной цепочки.
Если форма получена применением правила к самому левому нетерминалу в предыдущей форме, то она называется левой. Иначе — правой.
Пример
Убедимся в том, что язык
$S \rightarrow aSb$ $S \rightarrow \lambda$
Рассмотрим вывод терминальной цепочки:
$ab$ - терминалы (см. соглашения)
Но тогда и слова
Ещё пример
Можем перейти к терминалам
Хотим загнать буквы А в конец, а B в начало. Будем менять местами буквы по второму правилу.
19.02.2019
pos = init + rate * 60;
// после лескического анализа превращается в...
id,15 <=> <id,2><+><id,3><*><const><;>
// cинтаксическому анализу всё равно, как называется переменная
// после ситанксического анализа превращается в...
=
/ \
id,1 +
/ \
id,2 *
/ \
id,3 const
//после семантического добавятся какие-то атрибуты
На каждой стадии – новый язык. Значит, нужны новые способы порождения\описания. А этот способ порождает распознаватель.
Вид грамматики | Распознаватель | Класс языков | |
---|---|---|---|
0 | Грамматика обычного вида | МТ | Рекурсивно перечислимые |
1 | Контекстно-зависимые | МТ с линейно ограниченной памятью (LBA) | КЗЯ |
2 | Контекстно-свободные | Недетерминированный автомат с магазинной памятью (PDA) | КСЯ |
3 | Праволинейные | ДКА | Регулярные языки |
Опр. Контекстно-зависимая грамматика — грамматика, все правила которой имеют вид
Опр. Язык обладает свойством
Опр. Контекстно-свободная грамматика — грамматика, все правила которой имеют вид
Опр. Праволинейные грамматики — грамматика, все правила которой имеют вид
Вспомним пример. Кажется, что это грамматика обычного вида.
Построим КСГ, которая породит язык выше. Порождаем цепочки, где букв
Из
Иерархия: регулярные
Опр. Упорядоченное дерево — дерево с заданным линейным порядком со следующими свойствами:
- Если
$x$ — сын узла$y$ , то$x \ge y$ - Если
$x \le y$ и они братья, то для всех сыновей$z$ узла$x$ :$z\le y$
Порядок, возникающий при обходе в глубину слева направо
Пример:
S₁
/ \
S₂ S₄
| / | \
λ₃ (₅ s₆ )₁₁
/ | \
(₇ s₈ )₁₀
|
λ₉
Опр. Дерево вывода цепочки
-
Узлы — нетерминалы, корень — аксиома, листья — терминалы или
$\lambda$ , причём у листьев, помеченных пустым словом нет братьев.Если у узла есть братья, то
$\lambda a$ схлопывается до$a$ -
Если у узла
$x$ все сыновья это некоторый набор$y_1, : … : y_n$ , таких, что$y_1 \le : ...: \le y_n$ , и узлы$x$ ,$y_1, : … : y_n$ помечены символами$X, Y_1, : … : Y_n$ , то$(X \rightarrow Y_1, : … : Y_n) \in P$ .Применили правило, в дереве появился куст вывода
-
Если все листья дерева имеют метки
$a_1 \le a_2 \le : … \le : a_n$ , то$\omega = a_1…a_n$ .Крона дерева задаёт цепочку
$\omega $
Опр. Вывод цепочки
Крона поддерева $T_i $ задаёт форму
$\alpha_i$
Опр. Поддерево
-
корень
$T'$ - корень$T$ -
Если узел
$x$ дерева$T$ $ \in T'$, то либо$x$ — лист в этом поддереве, либо все сыновья$x$ в$T$ $\in T'$ Если с узлом лежит хотя бы один его сын, то и все его сыновья тоже лежат.
Пример по последнему языку:
Основная роль дерева вывода — связь синтаксиса и семантики выводимой цепочки. Например, семантика компьютерной программы — алгоритм решения задачи, а дерево вывода описывает структуру программы, т.е. порядок выполнения машинных операций, необходимых для реализации алгоритма.
Наша любимая грамматика, которая порождает арифметику:
E
/|\
E + E - этот куст можно передвинуть влево, получится два разных дерева
| /|\ для одного и того же. Плохо.
x E * E
| |
x x
Опр. Грамматика однозначна, если
Следующая грамматика однозначна и эквивалентна предыдущей
- Правосторонний вывод и r-формы:$E \rightarrow E + T \rightarrow E+TF \rightarrow E+Tx \rightarrow E+Fx \rightarrow E+xx\rightarrow T+xx \rightarrow F+xx \rightarrow x+x*x$
- Левосторонний вывод и l-формы:$E \rightarrow E+T\rightarrow T+T \rightarrow F+T \rightarrow x+T \rightarrow x+TF \rightarrow x+FF \rightarrow x+xF\rightarrow x+xx $
Плата за однозначность — увеличение длины вывода.
Чем плохи неоднозначные грамматики? Во время синтаксического разбора будет невозможно определить дерево разбора единственным образом. Значит, непонятно, что хотел сказать этим автор.
26.02.19
Теорема. Праволинейная грамматика порождает регулярный язык.
Д-во:
Суть: построим автомат и по теореме Клини3 — готово.
Конечный автомат:
Пример
$a(b+cc)^*$ — чтобы построить грамматику, проще сначала нарисовать автомат, распознающий этот язык. Обозначим все состояния нетерминальными символами. А дальше - как в теореме выше, только в обратную сторону.
$S \rightarrow aA$
$A \rightarrow bA|cB|\lambda$
$B \rightarrow cA$
Хотим научиться удалять лишние вещи, которые не несут никакой пользы.
Опр. Нетерминал
== из него можно получить терминальную цепочку.
Опр. Нетерминал
== его можно получить из аксиомы.
Опр. Грамматика приведённая, если все её нетерминалы достижимые и производящие.
Пример
Производящие (producing):
Если среди производящих нетерминалов нет аксиомы, то язык пустой.
Достижимые (reachable):
Нахождение
-
$\Gamma_r^1 \leftarrow S$ ; -
$\Gamma_r^n = \Gamma_r^{n-1} \cup {A|(B \rightarrow \alpha A \beta) \in P, B \in \Gamma_r^{n-1})}$ .смотрим, какие нетерминалы есть справа и добавляем те, которых ещё нет в
$\Gamma_r$
Нахождение
-
$\Gamma_p^1 \leftarrow {A|(A \rightarrow \omega) \in P}$ ; -
$\Gamma_p^n = \Gamma_p^{n-1} \cup {A|(A \rightarrow \gamma) \in P, \gamma \in (\Sigma \cup \Gamma_p^{n-1})}$ .смотрим на достижимые из
$\Gamma_p^{n-1}$ нетерминалы;
Теорема. Для любой КСГ
Д-во:
КСГ
Находим
-
если
$S \notin \Gamma_p$ , то$G' = (\Sigma, \emptyset, \emptyset, \emptyset)$ -
иначе
$\tilde G= (\Sigma, \Gamma_p, \tilde P, S) $ $ \tilde P = {(A \rightarrow \gamma) \in P | A, \gamma \in (\Sigma \cup \Gamma_p)^*}$
Находим
$A \in (\Gamma_p)r$: $S \Rightarrow{\tilde G}^* \alpha A \beta \Rightarrow_{\tilde G}^* uwv$
Выкинули правила вывода, которые и так не могли участвовать в выводе терминальных цепочек.
Пример
Больше не будем рассматривать неприведённые грамматики
Опр.
Опр.
Хотим, чтобы это множество было пустым. Ну или хотя бы только с аксиомой. Потому что тогда нам жить станет проще (почему? Сократим грамматику?).
Чтобы от аннулирующих нетерминалов избавиться, нужно их найти
Пример
${A, C}$ ${A,C,B,E}$ ${A,C,B,E, S}$
Опр.
Теорема. Любая КС-грамматика эквивалентна
-
Если
$\lambda \in L(G)$ , то$\Gamma' = \Gamma \cup S'$ ,$P'=P\cup{(S' \rightarrow \lambda), (S' \rightarrow S))}$ Иначе
$\Gamma = \Gamma '$ ,$S = S'$ ,$P=P'$
Смысл: добавим аксиому, которая справа встречаться нигде не будет???
-
Построим
$Ann(G)$ . -
Рассмотрим бинарное отношение на множестве форм:
$\beta \preceq \gamma$ , если$\beta$ — подпоследовательность$\gamma$ и все символы$\gamma$ , которых нет в$\beta$ , аннулирующие.Условие
$\beta \preceq \gamma$ влечёт$\gamma \Rightarrow^*_G \beta$ $P' = \left {A \rightarrow \beta\left| \begin{array}{l} \beta \neq \lambda \\beta \preceq \gamma\(A \rightarrow \gamma) \in P \end{array} \right. \right}$
Взяли все исходные правила. В новую грамматику положили их "части"-подстроки, в которых либо присутствует, либо удалён каждый из аннулирующих нетерминалов.
-
Видно, что аннулирующие правила мы не взяли, поэтому она
$\lambda$ -свободная по определению.
-
$w \in L(G')$ $S \Rightarrow_{G'} \alpha_1 \Rightarrow_{G'}... \Rightarrow_{G'} \alpha_n = w$ Рассмотрим переход
$\alpha_{i} \Rightarrow_{G'} \alpha_{i+1}$ :-
$(A \rightarrow \beta) \in P' $ , значит, в$G$ $\exists (A \rightarrow \gamma) \in P$ . -
$\beta \preceq \gamma$ , значит,$\gamma=\eta_1\beta\eta_2$ . Из этого следует, что$(A \rightarrow \eta_1\beta\eta_2) \in P$ -
$\eta_1$ и$\eta_2$ — аннулирующие, значит, $\gamma \Rightarrow^_G \beta$, значит, $A \Rightarrow^_G \beta$. - И это верно для любых цепочек, то есть если $\gamma \Rightarrow^_{G'} \beta$ то и $\gamma \Rightarrow^_G \beta$
как построить такую же цепочку, используя другие правила? Непонятно.
-
-
$w \in L(G)$ Нарисуем дерево вывода
$T$ цепочки$w$ в грамматике$G$ Обрежем все поддеревья с "пустой" кроной, получим какое-то дерево
$T'$ Покажем, что
$T'$ — дерево вывода для$w$ в$G’$ :- Посмотрим на какой-нибудь внутренний узел
$x$ в$T'$ - Метки его сыновей в
$T’$ образуют цепочку$\beta$ - Метки его сыновей, которые остались в
$T$ — аннулирующие. Назовём её$\eta$ - Если объединить эти цепочки, то получим
$\gamma = \beta\eta$ , то есть$\beta \preceq \gamma$ . -
$\beta \neq \lambda$ , по построению$T’$ (все поддеревья с пустой кроной удалены)
Вот и всё, всё круто, в любом внутреннем узле дерева
$T’$ реализуется правило вывода грамматики$G'$ А ещё корень
$T’$ равен корню$T$ (аксиоме), значит, это дерево вывода$w$ в$G’$ - Посмотрим на какой-нибудь внутренний узел
05.03.2019
Нужна для доказательства важной теоремы, понадобится для алгоритма разбора.
Опр. Грамматика находится в ХНФ, если все её правила вывода имеют вид либо
Теорема. Любая КС грамматика эквивалентна некоторой грамматике в ХНФ.
Д-во. Конструктивное.
Пусть
- Для всех правил грамматики, у которых в правой части хотя бы 2 символа сделаем следующее:
$\forall A\rightarrow X_1...X_n$ ,$n>=2$
- если
$X_i $ — терминал, добавим новый нетерминал$X_i'$ и правило$X_i' \rightarrow X_i$ . Затем заменим вхождение терминала во всех правых частях на новый нетерминал.
Избавляемся от правил, где справа много терминалов.
- $A \rightarrow B $ — цепные правила. Что делать с ними? Заменим правую часть на всё, что выводится из
$B$ . Но что, если есть цепочка$A \rightarrow B \rightarrow … \rightarrow A$ (цикл)? Сначала нужно от них избавиться.
Опр. Грамматика циклическая, если существует такой нетерминал
Лемма. Любая грамматика эквивалентна некоторой ацикличной.
Д-во. Пусть
Мы рассматриваем только цепные правила, так как грамматика
$\lambda$ -свободная, то есть не возникнет ситуации$A \rightarrow BC \rightarrow AC \rightarrow A$ (если из$C$ выводится$\lambda$ )
Заменим все
Почему работает:
- Пока в правых частях есть хотя бы 3 нетерминала, заменим два идущих подряд нетерминала на новый.
Пример
Выведем
Приведём к ХНФ. Добавим $ A' \rightarrow a$ и
Найдём цикл:
Заменим тройные нетерминалы на двойные, добавим
Пусть есть
-
$xy$ содержит хотя бы одну помеченную позицию; -
$xzy$ содержит не более$m$ помеченных; - $ux^{n}zy^nv \in L $
$\forall n \in \N_0$ (накачка).
Помечено - выбираем какие-то символы
Д-во.
Пусть
-
Корень (вершина треугольника) — аксиома. Принадлежит пути.
-
Из двух (потому что ХНФ) потомков выберем того, из которого выводится больше выделенных позиций.
Точка ветвления — узел, у которого из обоих потомков выводится подслова
$w$ с помеченными позициямиЗамечание: каждая следующая точка ветвления порождает не менее половины помеченных позиций
$w$ от тех, что порождает предыдущая точка.Д-во:
БИ:
$i=0$ .$v_i$ — корень, порождает все$m$ помеченных позицийШИ: рассмотрим
$v_i$ :- не точка ветвления, тогда
$v_{i+1}$ порождает столько же точек ветвления, сколько и$v_i$ - точка ветвления, из двух сыновей выбираем потока с бо́льшим количеством выделенных позиций
- не точка ветвления, тогда
в
$\left.\begin{array}{}A_{нижнее} \Rightarrow^+ z\ A_{верхнее} \Rightarrow^+ xzy\end{array}\right} \Rightarrow A \Rightarrow^+xAy$
Тут надо нарисовать треугольник, и станет понятнее!
-
$A_{верхнее}$ — точка ветвления (*)$\Rightarrow$ $x$ или$y$ содержит хотя бы одну помеченную позицию. ($x, y$ - подслова) - в
$xzy$ не более$m$ помеченных позиций (по замечанию) $S \Rightarrow^+ uAv \Rightarrow^+ uxAyv\Rightarrow^+ ux^2Ay^2v \Rightarrow^+ ...$
Рандомный комментарий: для всех слов высота дерева вывода одинаковая! Для ХНФ.
Пример
12.03.19
следствие леммы Огдена
$xy \neq \lambda$ $|xzy| \leq m$ $ux^kzy^kv \in L, \forall k \in \N_0$
Суть: для любого КСЯ существуют натуральные константы такие, что любое слово определённой длины соответствует свойствам. Отсутствуют слова про выделенные позиции! То есть все символы выделены.
Приравнять
$n$ к$m$ и все позиции сделать выделенными.
На экзамене будет вопрос про лемму о накачке и её следствия! Лемму доказывать не надо! Лемму Огдена надо. А следствия те, что ниже!
Сл. 1. Язык
Если не можем накачать слово, то это точно не КСЯ
Д-во: О.П: пусть язык
-
Накачиваться будет одна буква:
$a^{l+r}b^lc^l \not \in L$ -
Если
$x$ будет и в$a$ , и в$b$ , получиться$a$ после$b$ , такое слово$\not \in L$ .Значит,
$x$ лежит целиком в блоке$a$ ,$y$ целиком в блоке$b$ . Накачаем:$a^{l+r}b^{l+s}c^l \not \in L$ .
Сл. 2. Язык
Д-во: О.П.
$l > m$ $2|w| \ge n$
Накачать можем одну из половинок или что-то посередине.
-
Накачаем вторую половину. Количество одинаковых букв
$l$ больше, чем$m$ — максимальная длина накачиваемого слова. Значит, мы либо накачиваем одну букву$a_k$ , либо$a_k$ и$a_{k+1}$ .В левой половине (которую мы не накачивали) теперь $kl$ букв, а в правой — $kl + r$. Если сейчас поделим слово пополам, то снова должно получиться "квадратное" слово. Но, левая половина теперь будет кончаться на
$a_1$ , а вторая — на$a_k$ .|$w|a_1^l$][$….w'..a_k$]
$\uparrow$ новая граница -
Качаем посерединке
$a_1^l…a_k^{l+r} a_1^{l+s}…a_k^l $ ,$r+s \le m$ Б.О.О.$r \ge s$ -
$r = s$ $\Rightarrow$ в новом слове правая половина кончается на большее кол-во$a_k$ -
$r > s$ первая половина начинается на$a_1$ , вторая - на$a_k$
-
Лемма о накачке не всесильна:
$a^nb^nv^k, k \ge n$ См. доказательство по ссылке
Пример унарного языка:
$a^{n^r}$
Для языка
-
$L$ — регулярный; -
$L$ — КСЯ; -
мн-во длин слов из
$L$ — периодическое.$М \subseteq \N$ — периодическое, если$\exists n_0, d \in \N: \forall n > n_0 :(n \in M) \Rightarrow (n+d \in M)$
Д-во:
-
2
$\Rightarrow$ 3$\exists n,m : \forall a^n a^{n+r}; (r \le m)$ :$a^n=$ [по лемме о накачке]$=uxzyv=$[потому что язык унарный]$=uvzxy$$uvz(xy)^k \in L$ Положим
$n_0=n$ (из леммы о накачке),$d = m!$ $m!$ делится на все$r \in {1,…,m}$ , значит,$a^{n+lm!} \in L$ . -
3
$\Rightarrow$ 1построим автомат
M — периодическое множество длин слов.
$\forall i : 0\le i < d$ найдём минимальное$k_i : k_i \in M, k_i \equiv i: mod:d$ . Если для какого-то$i$ $k_i$ не существует, положим его равным нулю.M — бесконечное
$\Rightarrow \exists i: : k_i > 0$ Рисунок мухоловки с ручкой длины
$k$ , обода длины$d$ $\forall j \in {0,…,k}$ сост.$q_j$ – заключительное$\iff a^j \in L$ Для остальных
$q_s$ – заключительное$\iff a^{s+rd} \in L$ -
1
$\Rightarrow$ 2 — очевидно.
Опр. Подстановка $\tau:2^{\Sigma^} \rightarrow 2^{\Delta^} $
-
$\tau (\lambda) = \lambda$ ; -
$\tau (a) \subseteq \Delta^*,; a \in \Sigma$ ; если a — слово, и выполняется пункт 3, то это гомоморфизм -
$\tau (a_1…a_n) = \tau(a_1)\cdot…\cdot\tau(a_n)$ ; -
$\tau (L) = \bigcup \limits_{w \in L} \tau (w)$ .
Гомоморфизм — частный случай подстановки, при котором образ любой буквы — язык из одного слова (
$\forall a \in \Sigma : \tau(a) = w \in \Delta^*$ )TODO: переписать
Пример.
Который показывает, что операции объединения, произведения и итерации — частные случаи подстановки.
Пусть
-
$L = {a_1,a_2}$ $\tau (L) = \tau (a_1) \cup \tau(a_2) = L_1 \cup L_2$ -
$L = {a_1a_2}$ $\tau (L) = \tau (a_1)\cdot \tau(a_2) = L_1\cdot L_2$ -
$L = {a_1}^*$ $\tau (L) = \tau ({a_1}^) = \tau (\bigcup \limits_{i=0}^\infty a_1^i) = \bigcup \limits_{i=0}^\infty \tau (a_1^i) = \bigcup \limits_{i=0}^\infty \tau (a_1)^i = \bigcup \limits_{i=0}^\infty L_1^i = L_1^$
Пусть $L \subseteq \Sigma ^$ — КСЯ, $\tau:2^{\Sigma^} \rightarrow 2^{\Delta^*}$ — подстановка:
Пусть
$\tau$ — подстановка из одного конечного алфавита в другой, такая, что для любой буквы исходного алфавита, язык$\tau (a)$ — контекстно-свободный
Тогда
Д-во:
Каждому символу исходного алфавита сопоставим новую грамматику, которая будет задавать подстановку:
Б.о.о. $ \Gamma \cap \Gamma_i = \emptyset$,
Первое условие, для того, чтобы отловить переход из исходной граммтики в подстановку. Второе значит, что множества нетерминалов рассматриваемых грамматик попарно не пересекаются.
Грамматика
То есть цепочку из исходных терминалов заменяем на подстановку, из которой можем получить что-то новенькое
$w \in L(H)$
Построим дерево вывода
Так как
$\Gamma_i$ , потому что мы могли не дойти до самого низа дерева, где появляются терминалы (см. определение стандартного дерева)
Если
Если метка какого-то внутреннего узла лежит в
$\Gamma$ , а метка его ребёнка — нет, то метка ребёнка — это какая-то из аксиом грамматик$G_i$ . Больше никаких вариантов нет, так как$B$ принадлежит либо$\Gamma$ , либо$\Gamma_i$ . Если это будет не$S_i$ , то и$A$ должно принадлежать$\Gamma_i$ , что противоречит изначальному условию.
-
$S_{i_j} \Rightarrow_{G_{i_j}}^* a_{i_j}$ , т.е.$w_{i_j} \in \tau(a_{i_j})$ Аксиома
$S_{i_j}$ принадлежит грамматике$G_{i_j}$ , в которой любое слово$w_{i_j}$ — подстановка символа$a_{i_j}$
Значит,
“$\in$”, а не “$=$”, потому что результат подстановки — множество.
Значит,
$w \in \tau(L)$
19.03.2019
Сл. 1. Класс КСЯ замкнут относительно регулярных операций
Сл. 2. Класс КСЯ замкнут относительно перехода к гомоморфным образам.
Гомоморфизм — частный случай подстановки. Применение подстановки к одному символу даёт язык из одного слова
подстановка: $\tau(a) \subseteq \Sigma^$ гомоморфизм: $\phi(a) \in \Sigma^
$, т.е. $ \phi(a) = L, |L| = 1$
Предложение. Класс КСЯ не замкнут относительно пересечения и дополнения.
Д-во:
Пересечение:
Языки получены с помощью произведения КСЯ на КСЯ, значит, тоже КСЯ
Дополнение:
Выражаются через незамкнутое пересечение:
Пересечение КСЯ с регулярным языком — КСЯ Д-во:
Рассматриваем лямбда-свободные грамматики!
А что случится, если она будет не лямбда свободной? Дырки и лишние состояния?
Что можно сказать про
Достаточно рассмотреть автоматы с единственным заключительным состоянием:
$A =:(\Sigma, \Gamma, \delta, q_0, f_i), f_i \in F$
$M = \bigcup \limits_{f_i \in F}^{} L(A_{f_i})$
Рассмотрим вспомогательную грамматику:
Правила вывода состоят из правил двух типов:
- Те, что получаются из грамматики:
Если
$A \rightarrow X_1X_2...X_n \in P$ , то$\forall$ набора состояний$p, q, r_1,...,r_{n-1} \in Q$ :$(q,A,p)\rightarrow (q, X_1, r_1)(r_1, X_2, r_2)...(r_{n-1}, X_n, p) \in \bar{P}$ - Те, по которым есть правила перехода в автомате и
$a\in \Sigma$ : Если$\delta (q,a) = p$ , то$(q,a,p)\rightarrow a \in \bar{P}$
Поскольку правила второго вида порождают только листья дерева вывода, то можно считать, что при выводе терминальной цепочки из аксиомы грамматики
По определению грамматики
$(q_0, S, f), q=q_0, p=f$
Вторая из стрелок выполнима только тогда, когда
В итоге терминальная цепочка выводима в
Мы знаем, что регулярный язык можно распознать за линейное время. Про КСЯ пока ничего не знаем. Но, есть теорема, которая отвечает на этот вопрос. Попытаемся определить вхождение слова в КСЯ.
Сначала нужно построить табличку. Пусть есть слово, которое мы проверяем:
Для любой подстроки слова существует нетерминал, из которого эта самая подстрока выводится. При этом, так как справа стоят два нетерминала, из них тоже выводятся подстроки этой подстроки
Таблица — верхнетреугольная матрица размера
Столбец - длина | |
---|---|
Строка - позиция | Нетерминалы, из которых можно вывести подстроку из данной позиции с заданной длиной. |
Первый столбец заполняется по правилам ХНФ (2):
Остальные столбцы заполним, перебрав все возможные "распилы" строки на 2 части:
Если в
Если в
Пример
1 | 2 | 3 | 4 | 5 | 6 | |
---|---|---|---|---|---|---|
1 | A' | - | S, A | S, A | - | S |
2 | A' | S, A | A, B, C (acb) | - | - | |
3 | A,B,C | S, B, D | - (cbc) | S | ||
4 | B' | - (с B' ничего не начинается) | - (bcb) | |||
5 | A,B,C | S, B, D | ||||
6 | B' |
- с позиции 1 длины 1 + с позиции 2 длины 2;
- с позиции 1 длины 2 + с позиции 3 длины 1.
Смысл: берём значение из ячейки слева (
Сложность:
26.03.2019
Автоматы с магазинной памятью — стеком, PDA — push-down automaton.
|с|л|о|в|о|…|$\dashv$| — входная лента
Можем остаться на месте, или сдвинуться вправо
Автомат закончит работу, когда дочитает строку и остановится в заключительном состоянии.
Опр. МП-автомат
-
$\Sigma$ — входной алфавит; -
$\Gamma$ — стековый алфавит; -
$Q$ — множество состояний; -
$\delta$ — множество команд вида$(\cdot)$ ; -
$i_0$ — начальное состояние; -
$F$ — множество заключительных состояний; -
$\gamma_0 \in \Gamma^*$ — начальное состояние для стека.
Управляющая таблица для МП-автомата: по столбцам — символ, который читаем, по строкам — состояния и элемент на верхушке стека
Сколько мест в стеке, столько строк на каждое состояние
На каждом шаге обязательно надо читать из стека! Элемент при этом оттуда исчезает. Поэтому, если мы хотим, чтобы внизу всегда был символ ИКС, то в каждой команде нужно не забывать его туда класть.
в стеке будет лежать только открывающая скобка
При разборе — в левом префиксе открывающих скобок не меньше чем закрывающих
-
$(q, \dashv, B) \rightarrow \checkmark$ — команда допуска, слово читается. - пустота стека (можно добавить переходов, которые просто очищают стек).
Опр. Конфигурация автомата — снимок его состояния
-
$q$ — текущее состояние; -
$w$ — необработанная часть входной строки; -
$\gamma$ — текущее содержимое стека.
Вершина стека пишется слева! (пока)
На множестве конфигураций можно построить отношение: возможность перехода из одной конфигурации в другую.
Опр. МПА распознаёт цепочку, если он дочитал её до конца и:
- оказался в заключительном состоянии ИЛИ
- выполнил команду допуска ИЛИ
- закончил работу с пустым стеком
Опр. МПА распознаёт
Введение дополнительных стековых символов позволяет сократить количество состояний
Пример
Нужно следить, чтобы после
Когда будем пошагово воспроизводить работу МП-автомата, стек будем писать в правой колонке!
02.04.2019
ДМПА:
НМПА:
$fin$ — ограничиваем то, что складываем в стек, а то таблица станет бесконечной.
Теорема. Класс языков, распознаваемых НМПА, строго больше класса языков, распознаваемых ДМПА.
Д-во:
$\begin{array}{}X x, &\rightarrow\\lambda, &_\end{array}$ | $\begin{array}{}Xy, &\rightarrow\\lambda, &_\end{array}$ | |||
NB: вершина стека слева, запись
$X x, \rightarrow$ означает, что на вершине стека будет$X$
Суть таблички: пока не дошли до середины слова, закидываем текущий символ в стек, а наверху оставляем маркер. Как только дошли — снимаем его со стека (команда
$[\lambda,\ _]$ ). Затем просто ожидаем на входе те же символы, что и в стеке. Без проблем дошли до конца строки — это палиндром.
Что значит, что НМПА распознаёт символ?
Автомат с пустым стеком продолжать работу не может, так как на каждом шаге он что-нибудь берёт из стека.
О.П.
Давайте подадим ему на вход
Теорема. Любой КСЯ распознаётся НМПА с одним состоянием и одной командой допуска.
Д-во:
Если состояние одно, то нигде про него говорить не будем. Поэтому тройки станут двойками.
У нас остаётся входной и стековый алфавит
-
$(\nabla, \dashv) \rightarrow \checkmark$ -
$\forall a \in \Sigma : (a, a) \rightarrow (\lambda, \rightarrow)$ -
$\forall a \in \Sigma: (B, a) \rightarrow (\gamma, _)$ $\forall (B \rightarrow \gamma) \in P$
Простыми словами:
Заканчиваем работу успешно, если стек пуст, а входная строка дочитана до конца
Читаем символ входной строки только тогда, когда, когда на вершине стека — этот же символ
Для всех терминалов и для всех нетерминалов добавляем команду, которая будет “разворачивать” нетерминал по правилам из
$P$ .Команд будет столько, сколько разных правых частей есть для этого нетерминала.
-
$\Rightarrow$ $w \in L$ $\exists$ левосторонний вывод$w$ в$G$ $S \Rightarrow u_1B_1\gamma_1 \Rightarrow u_1u_2B_2\gamma_2 \Rightarrow … \Rightarrow u_1…u_{n-1}B_{n-1}\gamma_{n-1} \Rightarrow u_1…u_n$ Тогда в
$M$ реализуема следующая последовательность конфигураций$[w, S] = [u_1…u_{n}, S] \vDash [u_1…u_n, u_1B_1\gamma_1] \vDash^* [u_2…u_n,B_1\gamma_1] \vDash [u_2…u_n,u_2B_2\gamma_2] \vDash^*$ $ \vDash^* [u_n, B_{n-1}\gamma_{n-1}] \vDash [u_n, u_n] \vDash^* [\lambda, \lambda]$
$u_1$ — цепочка из терминалов$\gamma_i$ — цепочка из терминалов и нетерминаловПока мы не дойдём до нетерминала мы продолжим чтение входной строки
$B_{n-1}$ его правая часть — это какое-то правило, а левое — конец цепочки$\gamma_n$ -
$\Leftarrow$ $w \in L(M)$ Есть оракул, который говорит, что данная последовательность реализуема
$[w, S] \vDash^* [\lambda, \lambda]$
$\uparrow$ — конечное число тактов$m$ $w = a_1…a_m$ ,$a_i \in \Sigma \cup {\lambda}$ С помощью этой последовательности закодировали типы применяющихся команд. Если там лямбда, то мы применяли команду типа 2 и не сдвигались по входной строке.
$[w, S] \vDash [a_1…a_m, S] \vDash [a_1…a_m, a_{i_1}B_1\gamma_1] \vDash [a_{i_1+1}…a_m, B_1\gamma_1] \vDash ... \vDash [\lambda, \lambda]$
Вспомогательная лемма. Произведение обработанной части входной строки на содержимое стека — левая форма
Левая форма — всё, что может возникнуть в процессе левостороннего вывода.
Д-во. По индукции.
БИ: в прочитанном —
ПИ: обработанная часть:
ШИ:
-
прочитали из строки символ
$a_n \in \Sigma \Rightarrow \gamma_{n-1}=a_n\gamma_n$ .$\beta_{n-1} = \beta_n = a_1...a_n\gamma_n$ Прочитанное Остаток строки Стек
|
-
ничего из строки не прочитали
$a_n=\lambda \Rightarrow \gamma_{n-1}=B_{n-1}\gamma'_{n-1}$ $\beta_{n-1}=a_1…a_{n-1}B_{n-1}\gamma'_{n-1}$ $\beta_{n}=a_1…a_{n-1}\gamma\gamma'_{n-1}$ $(\beta_{n-1} \rightarrow \gamma) \in P$ Прочитанное Остаток строки Стек
|
Прочитанная строка не изменилась, значит, была применена команда вида (1) — мы раскрыли нетерминал с вершины стека по какому-то правилу из
Вернёмся к доказательству теоремы.
Что даёт теорема? Есть КСЯ, можем построить НМПА, его распознающий.
Теорема. Класс КСЯ и класс языков, распознающихся НМПА, совпадают.
Следствие. ДМПА распознаёт собственный подкласс КСЯ.
Пример
Стековый алфавит — все терминалы, нетерминалы и дно стека. В начале в стеке аксиома
$\begin{array}{}(S)S, &_\\lambda, &_\end{array}$ | $\begin{array}{}(S)S, &_\\lambda, &_\end{array}$ | ||
NB: не забываем, что вершина стека — слева!
Суть таблички: начинаем с аксиомы. Если во входной строке — скобочки, значит аксиому нужно “развернуть“. Если вложенные — то в нужный момент надо будет “развернуть” ещё раз. Если видим одинаковые скобки в стеке и во входной строке — считываем их. Если число закрывающих скобок в кусочке строки и в стеке одинаковое, то нужно убирать аксиомы с помощью правила с лямбдой.
Прочитаем
Слева — прочитанное, справа — стек. Наша цель — получить дерево
Прочитанное | Остаток строки | Стек |
---|---|---|