Генерация кода объектной программы

Генерация кода

Определение 4.13. Непосредственная генерация кода – это процесс порождения машинных команд по записи программы на промежуточном языке.
Задача генерации машинного кода обычно делится на две более простые задачи:
1) расчленение операций промежуточного языка на операции, эквивалентные машинным, и представление программы в виде псевдокода;
2) формирование компьютерных команд по псевдокоду.
При формировании псевдокода по промежуточной программе можно использовать заготовки. Продемонстрируем данную методику на примере преобразования дерева операций в код на языке ассемблера.
В качестве языка ассемблера возьмем язык ассемблера процессоров типа Intel 80x86. При этом будем считать, что операнды могут быть помещены в 16-разрядные регистры процессора и в коде результирующей объектной программы могут использоваться регистры АХ (аккумулятор) и DX (регистр данных), а также стек для хранения промежуточных результатов.
Введем обозначения:
1) Code(U) - функция, реализующая перевод данного узла U дерева в последовательность команд ассемблера;
2) operl, oper2 - операнды (листья дерева);
3) U1, U2 – узлы дерева, не являющиеся листьями;
4) act - обозначение одной из арифметических операций - сложения (+), вычитания (-), умножения (*) и деления (/), которым будут соответствовать команды ассемблера add, sub, mul и div.
Тогда четырём возможным формам текущего узла дерева для каждой арифметической операции будут соответствовать фрагменты кода на языке ассемблера, приведенные в таблице 4.5.

Таблица 4.5 - Преобразование узлов дерева операций в код на языке ассемблера для арифметических операций

Вид узла дерева

Результирующий код

mov ax, oper1
act ax, oper2

Code (U2)
mov dx, ax
mov ax, operl
act ax, dx

Code (U1)
act ax, ореr2

Code (U1)
push ax
Code (U2)
mov dx, ax
pop ax
act ax, dx

Семантика оператора присвоения требует, чтобы в левой части операции всегда был операнд, поэтому для нее возможны только два типа узлов дерева, влекущие порождение кода (два других типа узлов должны приводить к сообщению об ошибке). Заготовки для этой операции приведены в таблице 4.6.

Таблица 4.6 - Преобразование узлов дерева операций в код на языке ассемблера для операции присвоения

Вид узла дерева

Результирующий код

Овал: :=

mov ax, ореr2
mov operl, ax

 

Code (U2)
mov operl, ax

Пример 4.11. Рассмотрим в качестве примера выражение X:=Y*2-Z/3. Соответствующее ему дерево операций приведено на рисунке 4.7.

 

 

Рисунок 4.7 - Дерево операций для выражения X:=Y*2-Z/3

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

Шаг 1. Code(U2)
mov X, ax

Шаг 2. Code(U3)
push ax
Code(U4)
mov dx, ax        
pop ax
sub ax, dx
mov X, ax

Шаг 3. mov ax, Y
mul 2
push ax
Code(U4)
mov dx, ax        
pop ax
sub ax, dx
mov X, ax

Шаг 4. mov ax, Y
mul 2
push ax
mov ax, Z
div 3
mov dx, ax
pop ax
sub ax, dx
mov X, ax