|
||||
Меню:
Главная
Форум
Литература: Программирование и ремонт Импульсные блоки питания Неисправности и замена Радиоэлектронная аппаратура Микросхема в ТА Рубрикатор ТА Кабельные линии Обмотки и изоляция Радиоаппаратура Гибкие диски часть 2 часть 3 часть 4 часть 5 Ремонт компьютера часть 2 Аналитика: Монтаж Справочник Электроника Мощные высокочастотные транзисторы 200 микросхем Полупроводники ч.1 Часть 2 Алгоритмические проблемы 500 микросхем 500 микросхем Сортировка и поиск Монады Передача сигнала Электроника Прием сигнала Телевидиние Проектирование Эвм Оптимизация Автомобильная электроника Поляковтрансиверы Форт Тензодатчик Силовые полевые транзисторы Распределение частот Резисторные и термопарные Оберон Открытые системы шифрования Удк |
[174] Выражение, которое нужно скомпилировать, чтобы получить значение переменной factorial - это выражение lambda, и значением его является процедура, вычисляющая факториалы. Compile обрабатывает его путем вызова compile-lambda. Compile-lambda компилирует тело процедуры, снабжает его меткой как новую точку входа и порождает команду, которая склеит тело процедуры по новой метке с окружением времени выполнения и присвоит значение регистру val. Затем порожденная последовательность перепрыгивает через скомпилированный код, который вставляется в этом месте. Сам код процедуры начинается с того, что окружение, где процедура определена, расширяется кадром, в котором формальный параметр n связывается с аргументом процедуры. Затем идет собственно тело процедуры. Поскольку код для определения значения переменной не изменяет регистр env, команды save и restore, которые показаны выше как возможные, не порождаются. (В этот момент не выполняется код процедуры по метке entry2, так что детали его работы с env значения не имеют.) Следовательно, наш скелет скомпилированного кода становится таким: (assign val (op make-compiled-procedure) (label entry2) (reg env)) (goto (label after-lambdal)) entry2 (assign env (op compiled-procedure-env) (reg proc)) (assign env (op extend-environment) (const (n)) (reg argl) (reg env)) ( скомпилированный код тела процедуры) after-lambdal (perform (op define-variable!) (const factorial) (reg val) (reg env)) (assign val (const ok)) Тело процедуры всегда компилируется (в compile-lambda-body) как последовательность команд с целевым регистром val и типом связи return. В данном случае в последовательности одно выражение if: (if (= n 1) l (* (factorial (- n 1)) n)) Compile-if порождает код, который сначала вычисляет предикат (с целью val), затем проверяет его значение и, если предикат ложен, обходит истинную ветвь. При вычислении предиката сохраняются env и continue, поскольку они могут потребоваться в оставшейся части выражения if. Поскольку выражение if последнее (и единственное) в последовательности, составляющей тело процедуры, оно имеет цель val и тип связи return, так что и истинная, и ложная ветви компилируются с целью val и типом связи return. (Это значит, что значение условного выражения, которое вычисляется одной из его ветвей, является значением процедуры.) (сохранить continue, env, если они изменяются предикатом и требуются в ветвях) (скомпилированный код предиката, цель val, связь next) ( восстановить continue, env, если они сохранялись) (test (op false?) (reg val)) (branch (label false-branch4) true-branch5 (скомпилированный код истинной ветви, цель val, связь return) false-branch4 (скомпилированный код ложной ветви, цель val, связь return) after-if3 Предикат (= n 1) является вызовом процедуры. Он ищет в окружении оператор (символ =) и помещает его значение в proc. Затем он собирает аргументы - 1 и значение n, - в argl. Затем он проверяет, лежит ли в proc примитив или составная процедура, и соответствующим образом переходит на ветвь элементарной или составной процедуры. Обе ветви приводят к метке after-call. Требование сохранять регистры при вычислении оператора и операндов не приводит ни к каким операциям сохранения, поскольку в этом случае вычисления не трогают нужные регистры. (assign proc (op lookup-variable-value) (const =) (reg env)) (assign val (const 1)) (assign argl (op list) (reg val)) (assign val (op lookup-variable-value) (const n) (reg env)) (assign argl (op cons) (reg val) (reg argl)) (test (op primitive-procedure?) (reg proc)) (branch (label primitive-branch17)) compiled-branch16 (assign continue (label after-call15)) (assign val (op compiled-procedure-entry) (reg proc)) (goto reg val) primitive-branch17 (assign val (op apply-primitive-procedure) (reg proc) (reg argl)) after-call15 Истинная ветвь, константа 1, компилируется (с целевым регистром val и типом связи return) в (assign val (const 1)) (goto (reg continue)) Код для ложной ветви является еще одним вызовом процедуры, где процедурой служит значение символа *, а аргументами - n и значение еще одного вызова (вызова factorial ). Каждый из этих вызовов устанавливает значения proc и argl, а также свои собственные ветви для элементарных и составных процедур. На рисунке 5.17 показан полный скомпилированный код для определения процедуры factorial. Заметим, что возможные команды save и restore для continue и env при вычислении предиката, указанные выше, на самом деле порождаются, поскольку эти регистры изменяются во время вызова процедуры в предикате и нужны для вызова процедуры и связи return в ветвях. ;; построить процедуру и обойти ее тело (assign val (op make-compiled-procedure) (label entry2) (reg env)) (goto (label after-lambda1)) entry2; вызовы factorial будут попадать сюда (assign env (op compiled-procedure-env) (reg proc)) (assign env (op extend-environment) (const (n)) (reg argl) (reg env)) ;; начинается собственно тело процедуры (save continue) (save env) ;; вычислить (= n 1) (assign proc (op lookup-variable-value) (const =) (reg env)) (assign val (const 1)) (assign argl (op list) (reg val)) (assign val (op lookup-variable-value) (const n) (reg env)) (assign argl (op cons) (reg val) (reg argl)) (test (op primitive-procedure?) (reg proc)) (branch (label primitive-branch17)) compiled-branch16 (assign continue (label after-call15)) (assign val (op compiled-procedure-entry) (reg proc)) (goto reg val) primitive-branch17 (assign val (op apply-primitive-procedure) (reg proc) (reg argl)) after-call15 ; здесь val содержит результат (= n 1) (restore env) (restore continue) (test (op false?) (reg val)) (branch (label false-branch4)) true-branch5 ; вернуть 1 (assign val (const 1)) (goto (reg continue)) false-branch4 ;; вычислить и вернуть (* (factorial (- n 1) n)) (assign proc (op lookup-variable-value) (const *) (reg env)) (save continue) (save proc) ; сохранить процедуру * (assign val (op lookup-variable-value) (const n) (reg env)) (assign argl (op list) (reg val)) (save argl) ; сохранить частичный список аргументов для * ;; вычислить (factorial (- n 1)) , еще один аргумент * (assign proc (op lookup-variable-value) (const factorial) (reg env)) (save proc) ; сохранить процедуру factorial Рис. 5.17: Скомпилированный код определения процедуры factorial. (Продолжение на следующей странице.) |
Среды: Smalltalk80 MicroCap Local bus Bios Pci 12С ML Микроконтроллеры: Atmel Intel Holtek AVR MSP430 Microchip Книги: Емкостный датчик 500 схем для радиолюбителей часть 2 (4) Структура компьютерных программ Автоматическая коммутация Кондиционирование и вентиляция Ошибки при монтаже Схемы звуковоспроизведения Дроссели для питания Блоки питания Детекторы перемещения Теория электропривода Адаптивное управление Измерение параметров Печатная плата pcad pcb Физика цвета Управлении софтверными проектами Математический аппарат Битовые строки Микроконтроллер nios Команды управления выполнением программы Перехода от ahdl к vhdl Холодный спай Усилители hi-fi Электронные часы Сердечники из распылённого железа Анализ алгоритмов 8-разрядные КМОП Классификация МПК История Устройства автоматики Системы и сети Частотность Справочник микросхем Вторичного электропитания Типы видеомониторов Радиобиблиотека Электронные системы Бесконтекстный язык Управление техническими системами Монтаж печатных плат Работа с коммуникациями Создание библиотечного компонента Нейрокомпьютерная техника Parser Пи-регулятор ч.1 ПИ-регулятор ч.2 Обработка списков Интегральные схемы Шина ISAВ Шина PCI Прикладная криптография Нетематическое: Взрывной автогидролиз Нечеткая логика Бытовые установки (укр) Автоматизация проектирования Сбор и защита Дискретная математика Kb радиостанция Энергетика Ретро: Прием в автомобиле Управление шаговым двигателем Магнитная запись Ремонт микроволновки Дискретные системы часть 2 | ||