
518
Глава 5. Вычисления на регистровых машинах
команд, которые подлежат исполнению с помощью путей данных машины-вычислителя
с явным управлением
34
.
По сравнению с интерпретацией, компиляция может дать большой выигрыш в эффек-
тивности исполнения программы. Это будет объяснено ниже , при обзоре компилятора. С
другой стороны, интерпретатор предоставляет более мощную среду для интерактивной
разработки программы и отладки, поскольку исполняемая исходная программа присут-
ствует во время выполнения, и ее можно исследовать и изменять. В дополнен ие к этому,
поскольку библиотека примитивов присутствует целиком, во время отладки можно кон-
струировать и добавл ять в систему новые программ ы.
Исходя из взаимно дополнительных преимуществ компиляции и интерпретации, со-
временные среды разработки программ следуют смешанной стратегии. Как правило, ин-
терпретаторы Лиспа устроены таким образом, что интерпретируемые и скомпилирован-
ные процедуры могут вызывать друг друга. Это позволяет программисту компилировать
те части программы, которые он считает отлажен ными, пользуясь при этом преимуще-
ством в эффективности, предоставляемом компиляцией, но при этом сохранять интер-
претационный режим выполнения для тех частей пр ограммы, которые находятся в гуще
интерактивной разработки и отладки. В разделе 5.5.7, после того, как компилятор будет
разработан, мы покажем, как построить его взаимодействие с нашим интерпретатором и
получить интегрированную систему разработки, состоящую из компилятора и интерпре-
татора.
Обзор компилятора
Наш компилятор во многом похож на наш интерпретатор, как по структуре, так и
по функции, которую он осуществляет. Соответственно, механизмы анализа выражений,
используемые компилятор ом, будут подобны тем же механизмам для интерпретатора. Бо-
лее того, чтобы упростить взаимодействие компилируемого и интерпретируемого кода,
мы постр оим компилятор так, чтобы порождаемый им код следовал тем же соглашениям,
что и интерпретатор: окружение будет храниться в регистре env, списки аргументов бу-
дут собираться в argl, применяемая процедура — в proc, процедуры будут возвращать
свое значение в val, а место, куда им следует вернуться, будет храниться в регистре
continue. В общем, компилятор переводит исходную програм му в объектную програм-
му, которая проделывает, в сущности, те же самые операции с регистрами, которые
провел бы интерпретатор при выполнении той же самой исходной программы.
Это описание подсказывает стратегию для реализации примитивного компил ятора:
разбирать выражение таким же образом, как это делает интерпретатор. Когда мы встре-
чаем команду работы с регистром, которую интерпретатор выполнил бы при работе с
выражением, мы эту команду не выполняем, а добавляем к порождаемой нами последо-
вательности. Полученная последовательность команд и буде т объектным кодом. Отсюда
видно преимущество в эффективности, которое компиляция имеет перед и нтерпретаци-
34
На самом деле, машина, исполняющая скомпилированный код, может быть проще, чем машина-
интерпретатор, поскольку регистры exp и unev мы использовать не будем. В интерпретаторе они исполь-
зовались для хранения невычисленных выражений. Однако при использовании компилятора эти выражения
встраиваются в компилируемый код, который будет выполняться на регистровой машине. По той же при-
чине нам не нужны машинные операции, работающие с синтаксисом выражений. Однако скомпилированный
код будет использовать некоторые дополнительные машинные операци и (представляющие скомпилированные
объекты-процедуры), которых не было в машине-вычислителе с явным управлением.