Скачиваний:
38
Добавлен:
01.05.2014
Размер:
765.95 Кб
Скачать

23.4. Ассемблер

Последняя стадия обработки, выполняемой компилятором, состоит в ассемблировании перемещаемой программы в абсолютную объектную программу. Предикат assemble(Code, Dictionary. ObjectCode),используя сформированные на предыдущее этапе компиляции программу Codeи словарь Dictionary,вырабатывает объектную программу. Ассемблирование проходит в два этапа. На первом этапе подсчитывается число команд в программе, вычисляются адреса всех образованных во время генерации кода меток и удаляются ненужные пустые операции. Приведенная таким образом в порядок программа далее расширяется добавлением команды останова обозначаемой как instr(hult,0),блоком из Lячеек памяти для PL-переменных и рабочими ячейками, используемыми в программе. Определенное пространство для ячеек памяти обозначается как block(L).На втором этапе ассемблирования определяются адреса PL-переменныхи временных переменных, используемых в программе. Предложение assemblerзапишется следующим образом:

assemble (Code, Dictionary, TidyCode) 

tidy_and_count(Code, l, N, TidyCode \ (instr(halt,0);block(L))),

N1:= N+1,

allocate(Dictionary, N1, N2).

L:= N2-NI.

С помощью предиката tidy_and_count (Code, M. N. TidyCode)производится преобразование программы Codeв программу TidyCode,в которой определены правильные адреса меток и удалены пустые операции. Процедурно выполнение предиката tidy_and_countсоответствует второму проходу по программе.Мявляется адресом начала программы, а Nпревышает на единицу адрес конца исходной программы. Таким образом, число фактических команд в программе Codeсоставляет N+1-М.Программа TidyCodeпредставляется с помощью разностной структуры, основанной на функторе «;».

В рекурсивном предложении tidy_and_countдемонстрируются техника использования разностных структур и приемы изменения числовых значений:

tidy_and_count((Codel; Code2), M, N, TCodel \TCode2) 

tidy_and_count(Codel ,M, Ml, TCodel\Rest),

tidy._and_count(Code2, M1, N, Rest\TCode2).

В программе встречаются примитивы трех типов: команды, метки и «пустое команды» по_ор.Команды обрабатываются обычным образом. Счетчик адреса увеличивается на единицу, и команда вводится в разностную структуру:

tidy_and_count(instr(X, Y),N, Nl, (instr(X,Y):Code)\Code) 

N1:=N+1.

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

tidy_and_count(label(N), N, N, Code \ Code).

tidy_and_count(no_op, N. N, Code \ Code).

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

Предикат allocate (Dictionary, М, N)имеет главным образом процедурную интерпретацию. В процессе генерации кода при построении словаря ячейки памяти связываются с каждой из PL-переменныхпрограммы и с временными переменными. необходимыми для вычисления выражений. Действие предиката allocateсостоит в назначении фактических ячеек памяти переменным и занесении ссылок на них в программу.

Поиск переменных производится путем обхода словаря Dictionary. Mявляется адресом ячейки памяти для первой переменной, а N-наединицу превышает адрес последней переменной. Порядок переменных имеет алфавитное соответствие порядку их расположения в словаре. Кроме того, программа превращает словарь в полную структуру данных. Предикат allocateопределяется следующими пред­ложениями:

а1locate (void, N,N).

allocate (dict(Name, N1, BeforeAfter), N0, N) 

allocate(Before, N0, Nl),

N2:=N1+1,

allocate(After, N2, N).

На рис. 23.7представлены результаты компиляции тестовых программ, содержащихся в программе 23.2.

Программа test1:

instr(load, 11); instr(divc, 2);instr(store, 12);

instr(load, 10); instr(sub, 12); instr (add, 9); instr(write, 0);

instr(halt,0);block(4)

Программа test2:

instr(load, 10); instr(sub, 11); instr (jumple, 7);

instr(load, 10); instr(store, 12);instr(jump, 9);

instr(load, 11); instr(store, 12);instr (halt.,0);

block(3)

Программа factorial:

instr(read,21);instr(loadc, 1);instr(store, 19);

instr(loadc, 1);

instr(store, 20); isntr(load, 19);instr(sub, 21);

instr(jumpge, 16);instr(load,19);instr(addc, 1);

isntr(store,19);instr(load,20);mstr(mul,19);

instr(store,20);mstr(jump,6);instr(load,20);

instr(write, 0); instr (halt, 0); block(3)

Рис. 23.7.Откомпилированный объектный код.

Упражнения к гл. 23

1.Расширьте компилятор так, чтобы он мог обрабатывать циклы типа repeat.Операторrepeatимеет следующую синтаксическую форму:

repeat <statement> until<test>.

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

program repeat;

begin i:= 1;

repeat begin

write(i);

i:=i+l;

end

until i = 11

end.

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

23.5. Дополнительные сведения

Представленное здесь описание компилятора основано на прекрасной статье Уоррена (Warren, 1980).

Соседние файлы в папке prolog14_end