1.6. Инструментарий для создания компиляторов
Создатели компиляторов, как и прочие программисты, могут с пользой применять такие программные инструменты, как отладчики, средства контроля версий, профайлеры и т.п. В главе 11, "Создание компилятора" мы узнаем об использовании некоторых из этих инструментов при реализации компиляторов. В дополнение к этим средствам может использоваться ряд более специализированных инструментов, которые будут вкратце рассмотрены в этом разделе. Подробнее они будут описаны в последующих главах книги.
Вскоре после написания первых компиляторов появились инструменты, облегчающие их создание. Такие системы получили названия компиляторов компиляторов, генераторов компиляторов или систем написания трансляторов. Как правило, они ориентированы на языки определенной модели и наиболее подходят для генерации компиляторов языков именно этой модели.
Например, можно предположить, что лексические анализаторы для всех языков, по сути, одинаковы — за исключением множеств ключевых слов и знаков. Многие компиляторы компиляторов используют фиксированные программы лексического анализа в генерируемых компиляторах. Эти программы пользуются только списком ключевых слов, и все, что требуется от пользователя, — предоставить этот список. Такой подход вполне корректен, но может оказаться неработоспособным, если необходимо распознавание нестандартных токенов, например идентификаторов, которые включают символы, отличающиеся от букв и цифр.
Некоторые инструменты созданы для автоматической разработки определенных компонентов компиляторов. Они используют специализированные языки для определения и реализации компонентов и применяют весьма интеллектуальные алгоритмы. Наиболее эффективные инструменты скрывают детали алгоритма генерации и производят компоненты, легко интегрируемые с остальными частями компилятора. Ниже представлен список некоторых инструментов для создания компиляторов.
1. Генераторы синтаксических анализаторов. Эти генераторы производят синтаксические анализаторы, обычно по входной информации, основанной на контекстно-свободной грамматике. В первых компиляторах синтаксический анализ был весьма неэффективен и трудоемок. В настоящее время эта фаза является одной из простейших при реализации. Многие "микроязыки", использовавшиеся при создании этой книги, такие как PIC ([245]) и EQN, реализованы за несколько дней с помощью анализатора, описанного в разделе 4.7. Многие генераторы синтаксических анализаторов используют мощные алгоритмы разбора, которые слишком сложны для ручной реализации.
2. Генераторы сканеров. Этот инструментарий автоматически генерирует лексические анализаторы, как правило, с использованием спецификаций, построенных на регулярных выражениях (об этом рассказывается в главе 3, "Лексический анализ"). В основном, лексические анализаторы действуют по принципу конечного автомата. Типичный генератор сканеров и его реализация описаны в разделах 3.5 и 3.8.
3. Средства синтаксически управляемой трансляции. С помощью данного инструментария создаются наборы программ прохода по дереву разбора (наподобие представленного на рис. 1.4) и генерации промежуточного кода. Основная идея состоит в одной или нескольких "трансляциях", связанных с каждым узлом дерева разбора; при этом каждая трансляция определяется с учетом соседних узлов дерева. Эти средства обсуждаются в главе 5, "Синтаксически управляемая трансляция".
4. Автоматические генераторы кода. Эти инструменты получают набор правил, которые указывают способ трансляции каждой операции промежуточного языка в определенный машинный язык. Правила должны быть достаточно детальны, чтобы обеспечить работу с различными способами доступа к данным. Например, переменные могут находиться в регистрах, фиксированных (статических) ячейках памяти или в стеке. В данном случае применяется технология "согласованных шаблонов". Инструкции промежуточного кода замещаются "шаблонами", которые представляют собой последовательности машинных инструкций, согласованные по способу хранения переменных. Поскольку обычно имеется множество вариантов размещения переменных (например, в одном из регистров или в памяти), возможно использование различных способов замещения промежуточного кода набором шаблонов. Необходимо выбрать хорошее замещение шаблонами, без перебора всех возможных вариантов и замедления компиляции. Подобные инструменты рассматриваются в главе 9, "Генерация кода".
5. Средства работы с потоком данных. Для получения оптимизированного выходного кода требуется проведение серьезного анализа потока данных, т.е. сбора и анализа информации о том, каким образом значения передаются из одной части программы в другую. Такие задачи могут быть решены, по сути, с помощью одинаковых программ, одна из которых рассматривается в разделе 10.11.