Ремонт принтеров, сканнеров, факсов и остальной офисной техники


назад Оглавление вперед




[170]

next, то истинная ветвь заканчивается переходом, обходящим код для ложной ветви, на метку, которая стоит в конце условного выражения.

(define (compile-if exp target linkage)

(let ((t-branch (make-label true-branch)) (f-branch (make-label false-branch)) (after-if (make-label after-if))) (let ((consequent-linkage

(if (eq? linkage next) after-if linkage))) (let ((p-code (compile (if-predicate exp) val next)) (c-code (compile

(if-consequent exp) target consequent-linkage)) (a-code

(compile (if-alternative exp) target linkage))) (preserving (env continue) p-code

(append-instruction-sequences (make-instruction-sequence (val) () ((test (op false?) (reg val)) (branch (label ,f-branch)))) (parallel-instruction-sequences (append-instruction-sequences t-branch c-code) (append-instruction-sequences f-branch a-code))

after-if))))))

При вычислении предиката сохраняется env, поскольку он может потребоваться в истинной и ложной ветке, и continue, поскольку он может потребоваться связующему коду в этих ветвях. Код для истинной и ложной ветви (которые не выполняются последовательно) склеивается с помощью особого комбинатора parallel-instruction-sequences, описанного в разделе 5.5.4.

Заметим, что поскольку cond является производным выражением, для его обработки компилятор должен только запустить преобразование cond->if, а затем скомпилировать получившееся выражение if.

Компиляция последовательностей

Компиляция последовательностей (тел процедур и явных выражений begin) происходит так же, как их выполнение. Компилируется каждое из выражений последовательности - последнее с типом связи, который указан для всей последовательности, а остальные с типом связи next (для того, чтобы потом выполнялись остальные выражения последовательности). Последовательности команд для отдельных выражений склеиваются и образуют единую последовательность, при этом сохраняются env (необходимый для остатка последовательности) и continue (возможно, требуемый для связи в конце последовательности).

(define (compile-sequence seq target linkage) (if (last-exp? seq)

(compile (first-exp seq) target linkage) (preserving (env continue) (compile (first-exp seq) target next) (compile-sequence (rest-exps seq) target linkage))))


Компиляция выражений lambda

Выражения lambda строят процедуры. Объектный код для выражения lambda должен иметь вид

(построить процедурный объект и присвоить его целевому регистру) ( связь )

Компилируя выражения lambda, мы одновременно генерируем код для тела процедуры. Несмотря на то, что во время построения процедурного объекта тело исполняться не будет, удобно вставить его в код сразу после кода для lambda. Если связь для выражения lambda - метка или return, никаких сложностей при этом не возникает. Если же у нас тип связи next, то нужно обойти код для тела процедуры, использовав связь, которая переходит на метку, вставляемую сразу вслед за телом. Таким образом, объектный код принимает вид

(построить процедурный объект и присвоить его целевому регистру) (код для указанной связи) либо (goto (label after-lambda)) (скомпилированное тело процедуры) after-lambda

Процедура compile-lambda порождает код, строящий процедурный объект, вслед за которым идет код тела процедуры. Процедурный объект порождается во время выполнения путем сочетания текущего окружения (окружения, в котором исполняется определение) и точки входа для скомпилированного тела процедуры (свежесгенерированной метки).38

(define (compile-lambda exp target linkage) (let ((proc-entry (make-label entry))

(after-lambda (make-label after-lambda))) (let ((lambda-linkage

(if (eq? linkage next) after-lambda linkage))) (append-instruction-sequences (tack-on-instruction-sequence (end-with-linkage lambda-linkage (make-instruction-sequence (env) (list target) ((assign ,target

(op make-compiled-procedure) (label ,proc-entry)

(reg env)))))

(compile-lambda-body exp proc-entry)) after-lambda))))

38 Нам потребуются машинные операции, которые реализуют структуру данных, представляющую скомпилированные процедуры, аналогичную структуре для составных процедур, описанной в разделе 4.1.3:

(define (make-compiled-procedure entry env) (list compiled-procedure entry env))

(define (compiled-procedure? proc)

(tagged-list? proc compiled-procedure))

(define (compiled-procedure-entry c-proc) (cadr c-proc))

(define (compiled-procedure-env c-proc) (caddr c-proc))


В compile-lambda для того, чтобы добавить тело процедуры к коду lambda-выражения, используется специальный комбинатор tack-on-instruction-sequence (раздел 5.5.4), а не обыкновенный append-instruction-sequences, поскольку тело процедуры не является частью последовательности команд, выполняемой при входе в общую последовательность; оно стоит в последовательности только потому, что его удобно было сюда поместить.

Процедура compile-lambda-body строит код для тела процедуры. Этот код начинается с метки для точки входа. Затем идут команды, которые заставят машину во время выполнения войти в правильное окружение для вычисления тела - то есть окружение, где определена процедура, расширенное связываниями формальных параметров с аргументами, с которыми она вызвана. Затем следует код для последовательности выражений, составляющих тело процедуры. Последовательность эта компилируется с типом связи return и целевым регистром val, так что она закончится возвратом из процедуры с результатом в регистре val.

(define (compile-lambda-body exp proc-entry) (let ((formals (lambda-parameters exp))) (append-instruction-sequences (make-instruction-sequence (env proc argl) (env) (,proc-entry

(assign env (op compiled-procedure-env) (reg proc)) (assign env

(op extend-environment) (const ,formals) (reg argl)

(reg env))))

(compile-sequence (lambda-body exp) val return))))

5.5.3 Компиляция комбинаций

Соль процесса компиляции заключается в компилировании вызовов процедур. Код для комбинации, скомпилированный с данными целевым регистром и типом связи, имеет вид

(скомпилированный код оператора с целевым регистром proc и типом связи next)

(вычисление операндов и построение списка аргументов в argl) (скомпилированный код вызова процедуры с указанными целевым регистром и типом связи)

Во время вычисления оператора и операндов может потребоваться сохранить и восстановить регистры env, proc и argl. Заметим, что это единственное место в компиляторе, где указывается целевой регистр, отличный от val.

Требуемый код порождается процедурой compile-application. Она рекурсивно компилирует оператор, порождая код, который помещает подлежащую вызову процедуру в proc, и операнды, порождая код, который по одному вычисляет операнды процедурного вызова. Последовательности команд для операндов собираются (в процедуре construct-arglist) вместе с кодом, который строит список аргументов в регистре argl, а полученный код для порождения списка аргументов склеивается с кодом вычисления процедуры и кодом,



[стр.Начало] [стр.1] [стр.2] [стр.3] [стр.4] [стр.5] [стр.6] [стр.7] [стр.8] [стр.9] [стр.10] [стр.11] [стр.12] [стр.13] [стр.14] [стр.15] [стр.16] [стр.17] [стр.18] [стр.19] [стр.20] [стр.21] [стр.22] [стр.23] [стр.24] [стр.25] [стр.26] [стр.27] [стр.28] [стр.29] [стр.30] [стр.31] [стр.32] [стр.33] [стр.34] [стр.35] [стр.36] [стр.37] [стр.38] [стр.39] [стр.40] [стр.41] [стр.42] [стр.43] [стр.44] [стр.45] [стр.46] [стр.47] [стр.48] [стр.49] [стр.50] [стр.51] [стр.52] [стр.53] [стр.54] [стр.55] [стр.56] [стр.57] [стр.58] [стр.59] [стр.60] [стр.61] [стр.62] [стр.63] [стр.64] [стр.65] [стр.66] [стр.67] [стр.68] [стр.69] [стр.70] [стр.71] [стр.72] [стр.73] [стр.74] [стр.75] [стр.76] [стр.77] [стр.78] [стр.79] [стр.80] [стр.81] [стр.82] [стр.83] [стр.84] [стр.85] [стр.86] [стр.87] [стр.88] [стр.89] [стр.90] [стр.91] [стр.92] [стр.93] [стр.94] [стр.95] [стр.96] [стр.97] [стр.98] [стр.99] [стр.100] [стр.101] [стр.102] [стр.103] [стр.104] [стр.105] [стр.106] [стр.107] [стр.108] [стр.109] [стр.110] [стр.111] [стр.112] [стр.113] [стр.114] [стр.115] [стр.116] [стр.117] [стр.118] [стр.119] [стр.120] [стр.121] [стр.122] [стр.123] [стр.124] [стр.125] [стр.126] [стр.127] [стр.128] [стр.129] [стр.130] [стр.131] [стр.132] [стр.133] [стр.134] [стр.135] [стр.136] [стр.137] [стр.138] [стр.139] [стр.140] [стр.141] [стр.142] [стр.143] [стр.144] [стр.145] [стр.146] [стр.147] [стр.148] [стр.149] [стр.150] [стр.151] [стр.152] [стр.153] [стр.154] [стр.155] [стр.156] [стр.157] [стр.158] [стр.159] [стр.160] [стр.161] [стр.162] [стр.163] [стр.164] [стр.165] [стр.166] [стр.167] [стр.168] [стр.169] [стр.170] [стр.171] [стр.172] [стр.173] [стр.174] [стр.175] [стр.176] [стр.177] [стр.178] [стр.179] [стр.180] [стр.181] [стр.182] [стр.183] [стр.184] [стр.185] [стр.186] [стр.187] [стр.188] [стр.189] [стр.190] [стр.191] [стр.192] [стр.193] [стр.194] [стр.195] [стр.196]