- •Содержание
- •1 Формальные языки и грамматики
- •1.1 Основные понятия теории формальных языков
- •Определение Цепочка, которая не содержит ни одного символа, называется пустой цепочкой и обозначается .
- •1.2 Способы задания языков
- •1.2.1 Формальные грамматики
- •1.2.1.1 Определение формальной грамматики
- •Определение Цепочка (vtvn)* выводима из цепочки в грамматике(обозначается*), если существует последовательность цепочек (n0) такая, что .
- •1.2.1.3 Эквивалентность грамматик
- •1.2.2 Формы Бэкуса - Наура
- •1.2.3 Диаграммы Вирта
- •1.2.5 Механизмы распознавания языков
- •1.2.5.1 Определение распознавателя
- •1.2.5.2 Схема работы распознавателя
- •1.2.5.3 Классификация распознавателей
- •2 Регулярные грамматики и языки
- •2.1 Регулярные выражения
- •2.2 Лемма о разрастании языка
- •2.3 Конечные автоматы
- •2.3.1 Определение конечного автомата
- •2.3.2 Распознавание строк конечным автоматом
- •Существуют следующие способы представления функции переходов: - командный способ.Каждую команду ка записывают в форме , где.
- •2.3.3 Преобразование конечных автоматов
- •2.3.3.1 Преобразование конечного автомата к детерминированному виду
- •Алгоритм Преобразование нка в дка
- •2.3.3.2 Минимизация конечного автомата
- •2.3.3.2.1 Устранение недостижимых состояний ка
- •2.3.3.2.2 Объединение эквивалентных состояний ка Алгоритм Объединение эквивалентных состояний ка
- •2.4 Взаимосвязь способов определения грамматик
- •2.4.1 Построение ка по регулярной грамматике
- •Выход:ка.
- •3 Контекстно-свободные языки и грамматики
- •3.1 Задача разбора
- •3.1.1 Вывод цепочек
- •Определение Цепочка (vtvn)* выводима из цепочки в грамматике(обозначается*), если существует последовательность цепочек (n0) такая, что .
- •3.1.2 Дерево разбора
- •3.1.2.1 Нисходящее дерево разбора
- •3.1.2.2 Восходящее дерево разбора
- •3.1.3 Однозначность грамматик
- •3.2 Преобразование кс-грамматик
- •3.2.1 Проверка существования языка грамматики
- •3.2.2 Устранение недостижимых символов
- •Алгоритм Устранение нетерминалов, не порождающих терминальных строк Вход: кс-грамматика.
- •Алгоритм Устранение недостижимых символов Вход: кс-грамматика.
- •Определим множество достижимых символов z грамматики g, т.Е. Множество
- •3.2.3 Устранение -правил Алгоритм Устранение -правил Вход: кс-грамматика.
- •3.2.4 Устранение цепных правил Алгоритм Устранение цепных правил Вход: кс-грамматика.
- •3.2.5 Левая факторизация правил Алгоритм Устранение левой факторизации правил Вход: кс-грамматика.
- •3.2.6 Устранение прямой левой рекурсии Алгоритм Устранение прямой левой рекурсии Вход: кс-грамматика.
- •3.3 Автомат с магазинной памятью
- •3.3.1 Определение мп-автомата
- •3.3.2 Разновидности мп-автоматов
- •3.3.3 Взаимосвязь мп-автоматов и кс-грамматик
- •3.3.3.1 Построение мп-автомата по кс-грамматике
- •3.3.3.2 Построение расширенного мп-автомата по кс-грамматике
- •3.4 Нисходящие распознаватели языков
- •3.4.1 Рекурсивный спуск
- •3.4.1.1 Сущность метода
- •3.4.1.2 Достаточные условия применимости метода рекурсивного спуска
- •3.4.2 Распознаватели ll(k)-грамматик
- •3.4.2.1 Определение ll(k)-грамматики
- •3.4.2.2 Необходимое и достаточное условие ll(1)-грамматики
- •3.4.2.3 Построение множества first(1, a)
- •3.4.2.4 Построение множества follow(1, a)
- •3.4.2.5 Алгоритм «сдвиг-свертка» для ll(1)-грамматик
- •Шаг 6. Получили следующую цепочку вывода:
- •3.5.1.1.2 Поиск основы сентенции грамматики
- •3.5.1.1.3 Построение множеств l(a) и r(a)
- •3.5.1.1.5 Алгоритм «сдвиг - свертка» для грамматик простого предшествования
- •Шаг 3. Функционирование распознавателя для цепочки (((aa)a)a) показано в таблице 3.9.
- •3.5.1.2 Грамматика операторного предшествования
- •3.5.1.2.1 Определение грамматики операторного предшествования
- •3.5.1.2.2 Построение множеств Lt(a) и Rt(a)
- •3.5.1.2.4 Алгоритм «сдвиг-свертка» для грамматики операторного предшествования
- •3.5.2 Распознаватели lr(k)-грамматик
- •3.6 Соотношение классов кс-грамматик и кс-языков
- •3.6.1 Соотношение классов кс-грамматик
- •3.6.2 Соотношение классов кс-языков
- •4 Принципы построения языка
- •4.1 Лексика, синтаксис и семантика языка
- •4.2 Определение транслятора, компилятора, интерпретатора и ассемблера.
- •4.3 Общая схема работы компилятора
- •4.4 Лексический анализ
- •4.4.1 Задачи лексического анализа
- •4.4.2 Диаграмма состояний с действиями
- •4.4.3 Функция scanner
- •4.5 Синтаксический анализатор программы
- •4.5.1 Задача синтаксического анализатора
- •4.5.2 Нисходящий синтаксический анализ
- •Теорема Достаточные условия применимости метода рекурсивного спуска
- •4.6 Семантический анализ программы
- •4.6.1 Обработка описаний
- •4.6.2 Анализ выражений
- •4.6.3 Проверка правильности операторов
- •4.7 Генерация кода
- •4.7.1 Формы внутреннего представления программы
- •4.7.1.1 Тетрады
- •4.7.1.2 Триады
- •4.7.1.3 Синтаксические деревья
- •4.7.1.4 Польская инверсная запись
- •Составной оператор begin s1; s2;...; Sn end в полиЗе записывается как s1 s2... Sn.
- •4.7.1.5 Ассемблерный код и машинные команды
- •4.7.2 Преобразование дерева операций в код на языке ассемблера
- •4.8 Оптимизация кода
- •4.8.1 Сущность оптимизации кода
- •4.8.2 Критерии эффективности результирующей программы
- •4.8.3 Методы оптимизации кода
- •4.8.4 Оптимизация линейных участков программ
- •4.8.4.1 Свертка объектного кода
- •4.8.4.2 Исключение лишних операций
- •4.8.5 Оптимизация логических выражений
- •4.8.6 Оптимизация циклов
- •4.8.7 Оптимизация вызовов процедур и функций
- •4.8.9 Машинно-зависимые методы оптимизации
- •4.8.9.1 Распределение регистров процессора
- •4.8.9.2 Оптимизация кода для процессоров, допускающих распараллеливание вычислений
- •5 Формальные методы описания перевода
- •5.1 Синтаксически управляемый перевод
- •5.1.1 Схемы компиляции
- •5.1.4 Практическое применение су-схем
- •5.2 Транслирующие грамматики
- •5.2.1 Понятие т-грамматики
- •5.3 Атрибутные транслирующие грамматики
- •5.3.1 Синтезируемые и наследуемые атрибуты
- •5.3.2 Определение и свойства ат-грамматики
- •5.3.3 Формирование ат-грамматики
- •Решение
Составной оператор begin s1; s2;...; Sn end в полиЗе записывается как s1 s2... Sn.
Пример ПОЛИЗ оператораwhile n>3do begin write(n*n-1);n:=n-1endпредставлен в таблице 4.4
Таблица 4.4 – ПОЛИЗ оператора while
лексема |
n |
3 |
> |
19 |
!F |
n |
n |
* |
1 |
- |
W |
n |
n |
1 |
- |
:= |
1 |
! |
… |
номер |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
4.7.1.5 Ассемблерный код и машинные команды
Машинные команды удобны тем, что при их использовании внутреннее представление программы полностью соответствует объектному коду и сложные преобразования не требуются. Команды ассемблера представляют собой лишь формузаписи машинных команд, а потому в качестве формы внутреннего представления программы практически ничем не отличаются от них.
Однако использование команд ассемблера или машинных команд для внутреннего представления программы требует дополнительных структур для отображения взаимосвязи операций. Очевидно, что в этом случае внутреннее представление программы получается зависимым от архитектуры вычислительной системы, на которую ориентирован результирующий код. Значит, при ориентации компилятора на другой результирующий код потребуется перестраивать как само внутреннее представление программы, так и методы его обработки (при использовании триад или тетрад этого не требуется).
Тем не менее, машинные команды — это язык, на котором должна быть записана результирующая программа. Поэтому компилятор, так или иначе, должен работать с ними. Кроме того, только обрабатывая машинные команды (или их представление в форме команд ассемблера), можно добиться наиболее эффективной результирующей программы. Отсюда следует, что любой компилятор работает с представлением результирующей программы в форме машинных команд, однакоих обработка происходит, как правило, на завершающих этапах фазы генерации кода.
4.7.2 Преобразование дерева операций в код на языке ассемблера
В качестве языка ассемблера возьмем язык ассемблера процессоров типа Intel 80x86. При этом будем считать, что операнды могут быть помещены в 16-разрядные регистры процессора и в коде результирующей объектной программы могутиспользоваться регистры АХ (аккумулятор) и DX (регистр данных), а также стек для хранения промежуточных результатов.
Функцию, реализующую перевод узла дерева в последовательность команд ассемблера, назовемCode. Входными данными функции должна быть информацияоб узле дерева операций. В ее реализации на каком-либо языке программирования эти данные можно представить в виде указателя на соответствующий узел дерева операций. Выходными данными является последовательность команд языка ассемблера. Будем считать, что она передается в виде строки, возвращаемой в качестве результата функции.
Тогда четырём формам текущего узла дерева для каждой арифметической операции будут соответствовать фрагменты кода на языке ассемблера, приведенные в табл. 4.7.3.
Каждой допустимой арифметической операции будет соответствовать своя команда на языке ассемблера. Если взять в качестве примера операции сложения (+), вычитания (-), умножения (*) и деления (/), то им будут соответствовать команды add, sub, mul и div. Причем в ассемблере Intel 80x86 от типа операции зависит не только тип, но и синтаксис команды (операции mul и div в качестве первого операнда всегда предполагают регистр процессора АХ, который не нужно указывать в команде). Соответствующая команда должна записываться вместо act при порождении кода в зависимости от типа узла дерева.
Таблица 4.5 - Преобразование узлов дерева вывода в код на языке ассемблера для арифметических операций
Вид узла дерева |
Результирующий код |
Примечание |
mov ax, operl act ax, oper2
|
act — команда соответствующей операции operl, oper2 — операнды (листья дерева)
| |
Code (Узел 2) mov dx, ax mov ax, operl act ax, dx |
Узел 2 -нижележащий узел (не лист!) дерева Code (Узел 2) -код, порождаемый процедурой для нижележащего узла | |
Code (Узел 2) act ax, орег2 |
Code (Узел 2) — код, порождаемый процедурой для нижележащего узла | |
Code (Узел 2) push ax Code (УзелЗ) mov dx, ax pop ax act ax, dx |
Code (Узел 2) — код, порождаемый процедурой для нижележащего узла Code (Узел 3) -- код, порождаемый процедурой для нижележащего узла push и pop — команду сохранения результатов в стеке и извлечения результатов из стека |
Код, порождаемый для операции присвоения результата, будет отличаться от кода, порождаемого для арифметических операций. Кроме того, семантика языка требует, чтобы в левой части операции присвоения всегда был операнд, поэтому для нее возможны только два типа узлов дерева, влекущие порождение кода(два других типа узлов должны приводить к сообщению об ошибке, которая в компиляторе обнаруживается синтаксическим анализатором). Фрагменты кода для этой операции приведены ниже в таблице 4.6.
Таблица 4.6 - Преобразование узлов дерева вывода в код на языке ассемблера для операции присвоения
Вид узла дерева |
Результирующий код |
Примечание |
mov ax, орег2 mov operl, ax |
operl, oper2 — операнды (листья дерева)
| |
Code (Узел 2) mov operl, ax |
Узел 2 — нижележащий узел (не лист!) дерева Code (Узел 2)-код, порождаемый процедурой для нижележащего узла |
Теперь последовательность порождаемого кода определена для всех возможных типов узлов дерева»
Рассмотрим в качестве примера выражение A:-B*C+D-B*10. Соответствующее ему дерево вывода приведено на рис. 4.7.
Рисунок 4.7 Дерево операций для арифметического
выражения «A:=B*C+D-B*10»
Построим последовательность команд языка ассемблера, соответствующую дереву операций на рис. 4.7. Согласно принципу СУ-перевода, построение начинается от корня дерева. Для удобства иллюстрации рекурсивного построения последовательности команд все узлы дерева помечены от U1 до U5. Рассмотрим последовательность построения цепочки команд языка ассемблера по шагам рекурсии. Эта последовательность приведена ниже.
Шаг 1.
Code(U2)
mov A, ax
Шаг 2.
Code(U3)
push ax
Code(U5)
mov dx, ax
pop ax
sub ax, dx
mov A, ax
Шаг 3.
Code(U4)
add ax, D
push ax
Code(U5)
mov dx, ax
pop ax
sub ax, dx
mov A, ax
Шаг 4.
mov ax, В
mul С
add ax, D
push ax
Code(U5)
mov dx, ax
pop ax
sub ax, dx
mov A, ax
Шаг 5.
mov ax, В
mul С
add ax, D
push ax
mov ax, В
mul 10
mov dx, ax
pop ax
sub ax, dx
mov A, ax