Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Теория языков программирования и методы трансляции..pdf
Скачиваний:
28
Добавлен:
05.02.2023
Размер:
3.41 Mб
Скачать

229

5

2

6

12

 

 

 

 

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

Таким образом, во время генерации кода используются следующие структуры данных:

нижний стек;

верхний стек;

стек значений операций;

таблица блоков;

таблица видов и таблица символов из предыдущего прохода.

8.3ГЕНЕРАЦИЯ КОДА ДЛЯ ТИПИЧНЫХ КОНСТРУКЦИЙ

8.3.1 ПРИСВОЕНИЕ

· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·

В процессе присвоения

destination := source

значение, соответствующее источнику (source), присваивается значению получателя (destination), которое является адресом:

p := x + y (значение x + y присвоить p)

· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·

Допустим, что статические характеристики источника и получателя находятся в вершине нижнего стека. Последовательность действий: из ниж-

230

него стека удаляются два верхних элемента, затем выполняются следующие операции.

Проверяется непротиворечивость типов получателя и источника. Так как получатель представляет собой адрес, источник должен давать что-

нибудь приемлемое для присвоения этому адресу. В зависимости от реализу-

емого языка типы получателя и источника можно определенным образом ме-

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

Там, где необходимо, проверяются правила области действия (для не-

которых языков источник не может иметь меньшую область действия, чем получатель).

· · · · · · · · · · · · · · · · · · · · · · · ·

 

Пример · · · · · · · · · · · · · · · · · · · · · · ·

 

 

 

Например, в программе

begin

pointer real xx

begin

real x xx := x

end

end

присвоение недопустимо, и это может быть обнаружено во время компиля-

ции, если в таблице символов или в нижнем стеке имеется информация об области действия.

· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·

Для присвоения генерируется код, имеющий форму

ASSIGN type, S, D,

231

где S – адрес источника, D – адрес получателя.

Если язык ориентирован на выражения (то есть само присвоение имеет значение), статические характеристики этого значения помещаются в ниж-

ний стек.

8.3.2 УСЛОВНЫЕ ЗАВИСИМОСТИ

· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·

Условная зависимость имеет вид if B then C else D

· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·

При генерации кода для такой условной зависимости во время компи-

ляции выполняются три действия. Грамматика с включенными действиями имеет вид:

CONDITIONAL if B A1 then C A2 else D A3

Действия A1, A2, A3 означают (next – значение номера следующей метки,

присваиваемое компилятором):

A1. Проверить тип B, применяя любые необходимые преобразования типа для получения логического значения. Выдать код для перехода к L<next>, если B есть «ложь»:

JUMPF L<next>, <address of B>

Поместить в стек значение next (обычно для этого используется стек знаков операций). Увеличить next на 1. Угловые скобки использу-

ются для обозначения значений величин, заключенных в них.

A2. Генерировать код для перехода через ветвь else (то есть переход к концу условной зависимости):

GOTO L<next>

Удалить из стека номер метки (помещенный в стек действием A1),

назвать ее i, генерировать код для размещения метки:

SET LABEL L<i>

232

Поместить в стек значение next. Увеличить next на 1.

A3. Удалить из стека номер метки (j). Генерировать код для размещения метки:

SET LABEL L<j>

Если условная зависимость сама является выражением, компилятор должен знать, где хранить его значение, независимо от того, какая часть яв-

ляется then или else.

Аналогично можно обращаться с вложенными условными выражения-

ми.

8.3.3 ОПИСАНИЕ ИДЕНТИФИКАТОРОВ

Допустим, что типы всех идентификаторов выяснены в предыдущем проходе и помещены в таблицу символов. Адреса распределяются во время прохода, генерирующего код. Перечислим действия, выполняемые во время компиляции.

В таблице символов производится поиск записи, соответствующей идентификатору x.

Текущее значение указателя стека идентификаторов дает адрес, кото-

рый нужно выделить под x. Этот адрес

(idstack, current block number, instack pointer)

включается в таблицу символов, а указатель стека идентификаторов увели-

чивается на статический размер значения, соответствующего x.

Если x имеет динамическую часть (например, массив), то генерируется код для размещения динамической памяти во время прогона.

8.3.4 ЦИКЛЫ

· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·

Определим простейший цикл как

for i := 1 to 10 do <something>

233

· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·

Для генерации кода требуется четыре действия, которые размещаются следующим образом:

for i := 1 A1 to 10 A2 do A3 <something> A4

Эти действия таковы:

A1. Выделить память для управляющей переменной i. Поместить снача-

ла в эту память 1:

MOVE 1, address(<controlled variable>)

Здесь <controlled variable> – управляющая переменная цикла.

A2. Генерировать код для записи в память значения верхнего предела рабочего стека:

MOVE address (<ulimit>) <wostack>, <current block number>, <wostack pointer>,

где <wostack pointer> – указатель рабочего стека. Увеличить указа-

тель рабочего стека и уменьшить указатель нижнего стека, где хра-

нились статические характеристики верхнего предела.

A3. Поместить метку

SET LABEL L<next>

Увеличить next на 1. Выдать код для сравнения управляющей пере-

менной с верхним пределом и перейти к L<next>, если управляющая переменная больше верхнего предела:

JUMPG L<next>, address(<controlled variable>), address (<ulimit>)

Поместить в стек значение next. Поместить в стек значение (next

1). Увеличить next на 1.

A4. Генерировать код для увеличения управляющей переменной

PLUS address(<controlled variable>), 1

Удалить из стека номер (i). Генерировать код для перехода к L<i>: