Анимация
JavaScript


Главная  Библионтека 

0 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

Соответствующая часть транслятора выглядит следующим образом:

begin string label;

real (label);

print ((newline, X6, "BRN", X6, label)) end

Здесь значение Х6 есть строка, содержащая шесть пробелов. Если меткой будет L23, генерируется код

BRN L23

что означает < переход к метке L23».

3. Вызов стандартного знака операции

Параметрами являются конкретный знак операции, адреса операндов и адрес результата. знак операции может использоваться при вызове элемента внутреннего вариантного предложения для генерации соответствующего кода. Например, если знак операции - II + (сложение двух чисел), код может генерировать так:

begin address add1, add2, add3;

read ((add1, add2, add3)); convert(add1, 1); convert(add2, 2); convert(add3, 3);

print ((newline, X6, "LDX1 0 (1)", newline, X6, "ADX1 0(2)", newline, X6, "STO 1 0(3)"))

Допускается, что все адреса базированы в стеке. В результате выдается код

LDX 1 0 (1) ADX 1 0 (2) STO 1 0 (3)

Первая команда кода PLAN загружает в регистр 1 значение адреса, на который указывает регистр 1. Вторая команда складывает значение, содержащееся в адресе, на который указывает регистр 2, со значением, содержащимся в регистре 1 . Третья команда помещает в память содержимое регистра 1 по адресу, на который указывает регистр 3.

Convert также может генерировать какой-либо код. Например, если бы add1 находился в стеке идентификаторов в блоке 1 и имел вид

(idstack, 1, 4)

то генерировался бы следующий код:

LDX 1 DISPLAY + 1

AND 1 4



В результате в регистр 1 сначала загружались бы значение DISPLAY +1 и указатель на начало рамки стека, соответствующий блоку 1 , а затем к нему добавилось бы смещение адреса, и в итоге регистр 1 указывал бы на add1 . Если бы add1 находился в рабочем стеке, в регистр пришлось бы также добавить размеры статических областей, находящихся под областью рабочего стека в рамке

4. JUMPF

Параметрами служат метка и адрес времени прогона. Результатом команды является переход к метке, если значение, находящееся в адресе, окажется нулем («ложью»). Соответствующая часть транслятора имеет вид

begin string label;

address add1 ;

read ((label, add1));

convert(add1, 1);

print ((newline, X6, "LDX 1 0 (1)", newline, X6, "BZE 1" X2, label)) end

При метке L23, кроме вида, полученного от вызова convert, выдается также код

LDX 1 0(1)

BZE 1 L23

(BZE есть мнемоническое обозначение перехода при нулевом значении): 5. ASSIGN

Параметрами являются целое число (представляющее тип или указатель на таблицу видов), исходный адрес S и адрес получателя D. Во время компиляции выполняется действие:

begin int m: address add1, add2; read ((m, add1, add2)); convert (add1, 1); convert (add2, 2); scan (m) end

Scan генерирует код для переписывания элемента типа m из адреса, на который указывает регистр 1 , по адресу, указываемому регистром 2. Если тип простой, например real или int, то для этого потребуется лишь переписать значения одного или боле последовательных адресов с помощью команды MOVE в коде PLAN. Например, MOVE 1 2 перешлет содержимое двух последовательно расположеннтх адресов, начиная с адреса, на который указывает регистр 1 , в два последовательно расположенных адреса, начиная с адреса, на который указывает регистр 2, причем конечные значения этих регистров не изменятся. Вообще тип может быть структурой или массивом. В случае структуры scan применяется рекурсивно 1 и 2 после обращения с ними. Обработка массива, однако, сложнее. Очевидно, что статическую часть (т. е. описатель) переписывать необходимо, но нужно переписывать и динамическую часть (т. е. элементы самого массива). Для переписывания динамической части в регистры 1 и 2 вызываются scan с соответствующими указателями. Однако прежние значения регистров 1 и 2 не должны быть потеряны (представим, что массив был элементом какой-то структуры), и для хранения их значений, кроме всего прочего, требуется стек. Он должен иметь произвольный размер, так как типы могут быть произвольной



сложности. Тем не менее каждая реализация, по-видимому, накладывает свои (произвольные) ограничения на размер этого стека.

11.3. ОПТИМИЗАЦИЯ ОБЪЕКТНОГО КОДА

Как отмечалось в гл. 10, компиляторы отличаются по степени оптимизации выдаваемого объектного кода, направленной на то, чтобы программа проходила за возможно более короткое время. Выполнение некоторых видов локальной (< узкой») оптимизации почти всегда оправдано. Опишем кратко такую оптимизацию. Рассмотрим три последовательности объектного кода:

1. ldx1 2

ldx 2 1

После загрузки содержимого регистра 2 в регистр 1, несомненно, последует загрузка содержимого регистра 1 в регистр 2, что будет указываться в следующей же команде. Вторая команда (тем более, что она не имеет метки) явно избыточна и ее можно исключить

2. brn l23

команды без меток

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

3. brn l2 l2 brn l1

В этом случае тот же результат можно получить, заменив первую команду на brn l1 . Такие виды оптимизации выполняются во время генерации кода. Они легко осуществимы в смысле времени компиляции.

Упражнения

11.1 Каковы преимущества и недостатки метода компиляции в код Ассемблера, а не непосредственно в машинный код?

11.2. Напишите алгоритмы трансляции следующих команд промежуточного кода, которые были приведены в гл. 10: 1. MOVE

2. JUMPG

11.3. Какое дополнительное действие придется предпринять процедуре convert при обращении к косвенными адресами?

11.4. Какие осложнения может вызвать передача меток в виде целхх чисел (т.е. 23, а не L23) в командах промежуточного кода?

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

11.6. Как вы предполагаете, при каких обстоятельствах транслятор будет генерировать вызовы подпрограмм в коде Ассемблера?

11.7. В результате выполнения процедуры convert в регистр могло бы помещаться значение, а не указатель на это значение. Объясните, почему первый вариант не принят.

11.8. Присвоение в Алголе 68, например, обычно требует просмотра видов. В каких еще случаях может оказаться необходимым просмотр видов?

11.9. Укажите, что может потребоваться для реализации «узких» видов оптимизации, описанных в разд. 11.3?

11.10. Третья оптимизация в разд. 11.3 предполагает, что в двух последовательных командах происходит два безусловных перехода. Какое решение возможно в более общем случае?



0 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