
- •Предисловие
- •Глава 1 введение в проблематику конструирования компиляторов
- •1.1. Понятие компилятора и его структура
- •1.2. Применение компиляторов и задачи их разработки
- •Глава 2 способы задания формальных языков
- •2.1. Математический аппарат теории
- •Формальных языков, перевода и компиляции
- •1) AR*a для всех aÎa;
- •2.2 Цепочки и языки
- •2.3 Грамматики
- •2.4. Распознаватели
- •2.5 Регулярные выражения и синтаксические диаграммы
- •2.6. Автоматы с магазинной памятью (мп - автоматы )
- •2.7. Соответствия между способами описания языков
- •Глава 3 основы теории перевода
- •3.1. Определение перевода
- •3.2. Модели простейших трансляторов
- •3.2.1. Конечные преобразователи
- •3.2.2. Преобразователи с магазинной памятью
- •Глава 4 конструирование сканеров
- •4.1. Общая характеристика процесса сканирования
- •4.2. Описание лексем в языке расширенных регулярных выражений
- •4.3. Построение недетерминированного конечного автомата по расширенному регулярному выражению
- •4.4. Преобразование недетерминированного конечного автомата в детерминированный
- •Замечание. Среди состояний могут оказаться недостижимые состояния . Состояние р называется достижимым , если существует такая цепочка w , что (q0, w) *(p , e ). ¨
- •4.5. Преобразование синтаксической диаграммы в конечный автомат
- •4.6. Представление результатов сканирования
- •4.7. Методики конструирования сканеров
- •Глава 5 конструирование однопроходных нисходящих анализаторов
- •5.1. Определение синтаксического разбора
- •5.2. Нисходящий и восходящий разборы
- •5.3. Ll(k) - грамматики
- •5.4. Предсказывающие алгоритмы разбора
- •5.5. Алгоритмы построения управляющих таблиц для левых анализаторов
- •5.6. Приведение грамматик к ll - форме
- •Глава 6 основы генерации кода
- •6.1. Перевод и генерация кода
- •6.2. Представления промежуточной программы
- •6.3. Преобразование промежуточной программы в ассемблерный код
1) AR*a для всех aÎa;
2) aR*b, если aR+b.
т.е. R* получается добавлением к R+ всех пар (а,а):
.
Если формально
ввести степень отношения
,
считая, что
,
если a=b,
то
можно определить так:
.
Решетку,
представляющую отношение R,
можно преобразовать в
двоичную матрицу.
Для этого решетку
нужно повернуть на
по часовой стрелке
и помеченные узлы
повернутой решетки отобразить
в единичные элементы матрицы.
Представление в виде матрицы удобно для программной обработки отношений. Так, для нахождения Ri, R+, R* можно использовать соотношения:
где
- операции логического умножения и
сложения соответственно, а n
- такие, что
Пример
2.5. Пусть
и требуется найти
.
1. Представим R в виде решетки, а затем в виде матрицы:
2. Определяем все
степени
,
пока
(
-
по определению):
(нулевая матрица).
3. Определяем :
Окончательно имеем
Отображения.
Отображение М
множества А
в множество
В
- это такое отношение из А
в В,
что если (а,b)
и
.
Вместо записи
обычно пишут
M(a)=b, т.е.
отображение - это некоторая функция.
Используют также
запись вида
,
обозначающую отображение М
из А
в В,
при этом А -
это область
определения,
а В
- область
значений.
Говорят, что М(а)
определено,
если существует такое
,
что
M(a)=b (или (a,b)ÎM). Если М(а)=b определено для всех aÎA, то говорят, что М всюду определено.
При определении различных математических машин (конечных автоматов, преобразователей и др.) в теории формальных языков, синтаксического анализа и перевода нередко используются такие отображения , что А и В являются декартовыми произведениями других множеств (или содержатся в этих произведениях).
Пример
2.6. Пусть
задано отображение
,
где
- некоторые множества. Тогда элементами
М
являются пары вида:
и М
задается соотношениями вида М(c,d,e)={g,f}.
Приведенные здесь понятия будут использоваться уже в этой главе, другие понятия и определения будут вводиться по мере возникновения в них необходимости.
2.2 Цепочки и языки
Программа, написанная на языке программирования, состоит из операторов (команд, инструкций), которые, в свою очередь, состоят из символьных цепочек. Введем некоторые понятия и обозначения, касающиеся цепочек и языков:
символ (буква, знак)- неопределяемые термины;
алфавит S- множество символов;
цепочка - последовательность символов, расположенных (записанных) один за другим;
слово, строка, предложение- синонимы цепочки.
Обозначения:
е- пустая цепочка(не содержащая символов);
- цепочка из i
символов "a"
;
|x|- длина цепочки x (количество символов в ней).
Цепочка в алфавите S вводится рекурсивно, посредством следующих утверждений:
1) е- цепочка в S;
2) если x- цепочка в S и aÎS-, то ха- цепочка в S;
3) у- цепочка в S тогда и только тогда, когда она является таковой в силу п.1 или п.2.
Пусть x,y,z-произвольные цепочки в алфавите S. Тогда:
а) х называется префиксом цепочки ху, а у-суффиксом;
б) у называется подцепочкой цепочки xyz (префикс и суффикс- тоже подцепочки).
Определим следующие операции над цепочками:
а) если х,у - цепочки , то цепочка ху называется конкатенацией (сцеплением) х и у;
б) обращением
цепочки х
(обозначается:
)
называется цепочка, записанная в обратном
порядке.
Рассмотрим следующие множества:
(итерация)
- это множество всех цепочек в алфавите
S,
включая е(ясно, что это бесконечное множество);
(положительная
итерация)-
это множество цепочек ненулевой
длины, т.е.
.
Пример 2.7. Пусть...S={0,1},тогда:
={e,0,1,00,11,01,001,010,111,...},
={0,1,00,11,01,001,010,111,...}.
Языком
L в алфавите S
называется некоторое множество цепочек
этого алфавита, т.е.
.
Пусть
-
язык в алфавите
,
а
-
язык в алфавите
.
Тогда язык
L1L2={xy|
xÎL1
и
yÎL2}
называется
конкатенацией
(сцеплением,
произведением) языков
и
.
Итерация языка L (обозначается L*) определяется следующим образом:
1)
={e};
2) Ln=LLn-1, для n³0;
3)
.
Примечание. Здесь и в дальнейшем знак “*”, расположенный вверху справа от символа обозначает итерацию, а между символами - умножение (например, a*F - умножение, С * - итерация C ).
Позитивная
итерация
определяется как
для n³1
и имеет
следующие свойства:
а) L+ = LL* = L*L;
б)
L*
= L+
{e}.
Пример 2.8.