- •Университет наяновой
- •М. А. Шамашов основные структуры данных и алгоритмы компиляции
- •Предисловие
- •Введение
- •1. Краткий обзор процесса компиляции
- •2. Лексический анализ
- •0123...9 Пробел
- •3. Организация таблиц компилятора
- •3.1. Общий вид таблиц
- •3.2. Прямой доступ к таблице или метод индексов
- •3.3. Неупорядоченная таблица или метод линейного списка
- •3.4. Упорядоченная таблица. Бинарный, двоичный или логарифмический поиск
- •3.5. Сбалансированные деревья
- •3.6. Деревья оптимального поиска
- •3.7.1. Рехеширование
- •3.7.3. Метод цепочек или гроздей
- •4. Общие методы синтаксического анализа
- •4.1. Нисходящий разбор с возвратами
- •4.2. Восходящий разбор с возвратами
- •4.3. Символьный препроцессор на основе бэктрекинга
- •4.3.1. Фаза анализа и перевода грамматики во внутреннее представление
- •4.3.2. Лексичекий анализ в сп
- •4.3.3. Синтаксический анализ в сп
- •4.3.4. Выполнение семантических действий
- •5. Однопроходный синтаксический анализ без возвратов
- •5.1. Ll(k) языки и грамматики
- •5.1.1. Предсказывающие алгоритмы разбора и разбор для ll(1)-грамматик
- •5.1.2. Рекурсивный спуск
- •5.2. Языки и грамматики простого предшествования
- •Xy, если u xy
- •X y, если u xU1) (y l(u1))
- •X y, если (u u1y) (X r(u1)) or
- •5.2.1. Алгоритм Вирта–Вебера для анализа языков простого предшествования
- •5.2.2. Функции предшествования.
- •5.2.3. Проблемы построения грамматик предшествования
- •5.3. Операторная грамматика предшествования
- •6. Введение в семантику
- •6.1. Внутренние формы исходной программы
- •6.1.1. Польская инверсная запись
- •If выр then инстр 1 else инстр 2
- •6.1.2. Интерпретация полиЗа
- •6.1.3. Генерирование команд по полиЗу
- •6.1.4. Тетрады и триады
- •6.2. Семантические подпрограммы перевода инфиксной записи в полиз и аспекты их реализации
- •6.3. Семантические подпрограммы для перевода в тетрады
- •6.4. Метод замельсона–бауэра для перевода в полиз и тетрады
- •6.5. Нейтрализация ошибок
- •6.5.1. Исправления орфографических ошибок
- •6.5.2. Нейтрализация семантических ошибок
- •6.5.3. Нейтрализация синтаксических ошибок
- •7. Машинно-независимая оптимизация программ
- •7.1. Исключение общих подвыражений
- •7.2. Вычисления во время компиляции
- •7.3. Оптимизация булевых выражений
- •7.4. Вынесение инвариантных вычислений за цикл
- •8. Машинно-зависимые фазы компиляции
- •8.1. Распределение памяти
- •8.2. Генерация кода и сборка
- •8.3. Трансляция с языка ассемблера
- •Заключение
- •Список литературы
- •Содержание
- •1. Краткий обзор процесса компиляции 5
- •2. Лексический анализ 10
- •3. Организация таблиц компилятора 16
- •4. Общие методы синтаксического анализа 28
- •5. Однопроходный синтаксический анализ без возвратов 52
- •6. Введение в семантику 78
- •7. Машинно-независимая оптимизация программ 102
- •8. Машинно-зависимые фазы компиляции 109
4.3.4. Выполнение семантических действий
В синтаксически управляемых трансляторах выполнение семантических процедур, перевод исходного текста всегда совмещен с процессом синтаксического анализа. Распознавание отдельного элемента или языковой конструкции влекло вызов подпрограмм и выполнение семантических действий. Это и привело к тому, что на практике возвратные алгоритмы анализа не нашли применения. Пройдя часть пути по одной из альтернатив той или иной продукции грамматики, и обнаружив расхождение, мы можем достаточно просто вернуться по пройденному тексту, и рассмотреть еще одну альтернативу. Но как аннулировать результаты семантических подпрограмм, которые уже были выполнены? Это принципиальное возражение теоретиков против возвратных алгоритмов трансляции. В рассматриваемом СП эта проблема достаточно просто решается введением еще одного просмотра – выполнения семантических действий, который осуществляется уже после корректного завершения синтаксического анализа. Это снижает эффективность проектируемого транслятора, увеличивает время трансляции, но это дает возможность рассматривать любые, в том числе и недетерминированные КС-языки, что зачастую и необходимо в учебных целях.
Файл семантических действий, формируемый в процессе синтаксического анализа, содержит протокол вызова процедур, реализующих семантические действия, и аргументы, с которыми они будут вызываться. В качестве аргумента семантической процедуры выступает последняя лексема исходного текста, сопоставленная с конструкцией грамматики непосредственно перед тем, как при грамматическом разборе в правой части продукции было встречено изображение оператора вызова данного семантического действия. Например, в результате успешного сопоставления продукций:
A @_IDN_@ (_2_)
или
A <_B_> (_2_)
B @_IDN_@
семантическая процедура с кодом 2 будет вызываться с параметром-лексемой “идентификатор”, отождествлённым с синтермом IDN.
Если в грамматике несколько ссылок на семантические процедуры стоят подряд, то эти процедуры будут вызываться с одним и тем же аргументом.
Например, для случая:
A ::= ... @_INT_@ (_1_)(_3_)(_5_)
семантические процедуры 1, 3, 5 будут вызываться с аргументом-лексемой “целое число”, отождествлённым с синтермом INT.
Семантика языков программирования – это тот раздел трансляции, который с очень большим трудом поддается формализации. Все известные автору попытки включения формального описания семантики в спецификацию языка не находят распространения. Формальное описание семантики слишком тяжеловесно и так называемые атрибутные или транслирующие грамматики чаще всего понятны только их составителям. В рассматриваемой системе написание набора семантических процедур возлагается на разработчика транслятора для конкретного языка.
В заключение раздела поясним принципы расстановки семантических атрибутов (номеров процедур) в спецификации языка для рассматриваемого СП на примере грамматики арифметических выражений:
Выражение ::= [_ <_ OTC _> (_0_) _] (_1_) <_ TEPM _> (_3_)
{_ <_ OTC _> (_2_) <_ TEPM _> (_3_) _}
TEPM ::= <_ множитель _>
{_ <_ OTM _> (_2_) <_ множитель _> (_3_) _}
множитель ::= ?_ ( <_ Выражение _> ) _|_ @_ IDN _@ (_4_) _|_
@_ REL _@ (_4_) _|_ @_ INT _@ (_4_) _?
OTC ::= ?_ + _|_ - _?
OTM ::= ?_ _|_ / _?
Здесь семантические действия призваны перевести заданное арифметическое выражение в ПОЛИЗ:
0 - Отметить наличие унарного минуса.
1 - Если был унарный минус, поместить его обозначение – символ ‘@’ в семантический стек и сбросить признак минуса, установленный действием 0-ой процедуры. В противном случае поместить в семантический стек символ ‘n’;
2 - Поместить символ операции (, , , ) в семантический стек;
3 - Выгрузить символ из семантического стека и, если он отличен от ‘n’, поместить его в выходную строку;
4 - Поместить идентификатор или константу в выходную строку.
Упражнения на программирование.
4.1. Разработайте программу, которая по произвольной заданной КС-грамматике строит эквивалентный недетерминированный МП-автомат, моделирующий левый вывод. Программа должна визуализировать грамматику, автомат и последовательность шагов, которые проделывает автомат, допуская или отвергая входную цепочку.
4.2. Разработайте программу, которая по произвольной заданной КС-грамматике строит эквивалентный недетерминированный расширенный МП-автомат, моделирующий отсечение основ. Программа должна визуализировать грамматику, автомат и последовательность шагов, которые проделывает автомат, допуская или отвергая входную цепочку.
4.3. Реализовать алгоритм нисходящего разбора с возвратами. Программа должна для заданной КС-грамматики и входной цепочки визуализировать шаги нисходящего разбора и построение дерева разбора.
4.4. Реализовать алгоритм восходящего разбора с возвратами. Программа должна для заданной КС-грамматики и входной цепочки визуализировать шаги восходящего разбора и построение дерева разбора.