В вычислении , генерация кода представляет собой процесс , с помощью которого компилятор «ы код генератор преобразует некоторое промежуточное представление из исходного кода в форме (например, машинный код ) , который может быть легко выполнен с помощью машины.
Сложные компиляторы обычно выполняют несколько проходов над различными промежуточными формами. Этот многоступенчатый процесс используются , потому что многие алгоритмы для оптимизации коды проще применять по одному, или потому , что вход в одной оптимизации зависит от завершенной обработки выполняется другой оптимизацией. Эта организация также облегчает создание единого компилятора, который может ориентироваться на несколько архитектур, поскольку только последний из этапов генерации кода ( бэкэнд ) должен изменяться от целевого к целевому. (Дополнительные сведения о конструкции компилятора см . В разделе « Компилятор» .)
Входные данные для генератора кода обычно состоят из дерева синтаксического анализа или абстрактного синтаксического дерева . [1] Дерево преобразуется в линейную последовательность инструкций, обычно на промежуточном языке, таком как трехадресный код . Дальнейшие этапы компиляции могут или не могут называться «генерацией кода», в зависимости от того, включают ли они значительные изменения в представлении программы. (Например, этап оптимизации с глазком вряд ли будет называться «генерацией кода», хотя генератор кода может включать этап оптимизации с глазком.)
Основные задачи
Помимо основного преобразования из промежуточного представления в линейную последовательность машинных инструкций, типичный генератор кода пытается каким-то образом оптимизировать сгенерированный код.
Задачи, которые обычно являются частью фазы «генерации кода» сложного компилятора, включают:
- Выбор инструкций : какие инструкции использовать.
- Планирование инструкций : в каком порядке размещать эти инструкции. Планирование - это оптимизация скорости, которая может иметь решающее влияние на конвейерные машины.
- Размещение регистров : размещение переменных в регистрах процессора [2]
- Генерация данных отладки, если требуется, чтобы код можно было отладить .
Выбор инструкций обычно выполняется путем выполнения рекурсивного обхода после порядка в абстрактном синтаксическом дереве, сопоставляя конкретные конфигурации дерева с шаблонами; например, дерево W := ADD(X,MUL(Y,Z))
может быть преобразовано в линейную последовательность инструкций путем рекурсивной генерации последовательностей для t1 := X
и t2 := MUL(Y,Z)
, а затем выдачи инструкции ADD W, t1, t2
.
В компиляторе, использующем промежуточный язык, может быть два этапа выбора инструкций - один для преобразования дерева синтаксического анализа в промежуточный код, а второй этап намного позже для преобразования промежуточного кода в инструкции из набора команд целевой машины. Эта вторая фаза не требует обхода дерева; это может быть выполнено линейно и обычно включает простую замену операций на промежуточном языке их соответствующими кодами операций . Однако, если компилятор на самом деле является переводчиком языка (например, тем, который преобразует Java в C ++ ), тогда вторая фаза генерации кода может включать построение дерева из линейного промежуточного кода.
Генерация кода во время выполнения
Когда генерация кода происходит во время выполнения , как при JIT -компиляции , важно, чтобы весь процесс был эффективным в отношении пространства и времени. Например, когда регулярные выражения интерпретируются и используются для генерации кода во время выполнения, недетерминированный конечный автомат часто генерируется вместо детерминированного, потому что обычно первый может быть создан быстрее и занимает меньше места в памяти, чем второй. Несмотря на то, что обычно генерируется менее эффективный код, генерация кода JIT может использовать информацию профилирования , доступную только во время выполнения.
Связанные понятия
Фундаментальная задача ввода ввода на одном языке и вывода вывода на нетривиально другом языке может быть понята в терминах основных трансформационных операций теории формального языка . Следовательно, некоторые методы, которые изначально были разработаны для использования в компиляторах, стали использоваться и другими способами. Например, YACC (Еще один компилятор-компилятор ) принимает ввод в Бакуса-Наура и преобразует его в анализатор в C . Хотя изначально он был создан для автоматического создания парсера для компилятора, yacc также часто используется для автоматизации написания кода, который необходимо изменять каждый раз при изменении спецификаций. [3]
Многие интегрированные среды разработки (IDE) поддерживают некоторую форму автоматической генерации исходного кода , часто используя алгоритмы, общие с генераторами кода компилятора, хотя обычно менее сложные. (Смотри также: преобразование программы , преобразование данных .)
Отражение
Как правило, синтаксический и семантический анализатор пытается извлечь структуру программы из исходного кода, в то время как генератор кода использует эту структурную информацию (например, типы данных ) для создания кода. Другими словами, первый добавляет информацию, а второй теряет часть информации. Одним из последствий этой потери информации является то, что размышление становится трудным или даже невозможным. Чтобы противостоять этой проблеме, генераторы кода часто встраивают синтаксическую и семантическую информацию в дополнение к коду, необходимому для выполнения.
Смотрите также
- Автоматическое программирование
- Сравнение инструментов генерации кода
- Компиляция из исходного кода в исходный : автоматический перевод компьютерной программы с одного языка программирования на другой.
Рекомендации
- ^ Стивен Мучник; Muchnick and Associates (15 августа 1997 г.). Продвинутая реализация проекта компилятора . Морган Кауфманн. ISBN 978-1-55860-320-2.
генерация кода.
- ^ Ахо, Альфред V .; Рави Сетхи; Джеффри Д. Ульман (1987). Компиляторы: принципы, методы и инструменты . Эддисон-Уэсли. п. 15. ISBN 0-201-10088-6.
- ^ Генерация кода: настоящий урок Rails . Artima.com (16 марта 2006 г.). Проверено 10 августа 2013.