- •Преобразование полиз в язык ассемблера
- •Введение
- •Входные данные
- •Модель исполнения полиз
- •Пример:
- •Особенности работы с данными в стеке исполнения
- •Описание перевода элементов полиз в язык ассемблера
- •Пример работы с данными в стеке исполнения
- •Описание перевода операций по работе с метками
- •Описание перевода операций по работе с памятью
- •Исходный код
- •Результат трансляции
- •Результат выполнения
Описание перевода операций по работе с метками
КомандаПОЛИЗ |
Перевод в ассемблер |
Пояснение |
@DEFL |
<имя метки>: |
Предусловие: В промежуточном стеке верхний элемент является меткой.
Вытолкнуть из промежуточного стека элемент, содержащий <имя метки>. |
@JMP |
jmp <имя метки> |
Предусловие: В промежуточном стеке верхний элемент является меткой.
Вытолкнуть из промежуточного стека элемент, содержащий <имя метки>. |
@JMPF |
pop eax cmp eax, 1 jne <имя метки>
|
Предусловие: В промежуточном стеке верхний элемент является переменной логического типа (4 байта, 0 – если false, 1 – еслиtrue), следующий за верхним элемент является меткой.
Вытолкнуть из промежуточного стека элемент. Вытолкнуть из промежуточного стека элемент, содержащий <имя метки>.
Постусловие: Данные в регистре eaxпотеряны. |
Описание перевода операций по работе с памятью
КомандаПОЛИЗ |
Перевод в ассемблер |
Пояснение |
@SET |
push <размер типа в байтах> call __copy_memory add esp, 12 |
Предусловие: Оба верхних элемента в промежуточном стеке являются указателями на переменные.
Узнать тип, на который указывают указатели, и определить его <размер в байтах>. Вытолкнуть из промежуточного стека два элемента.
Постусловие: Содержимое памяти по данным указателям идентично. |
__set_integer_variable |
Предусловие: Верхний элемент в промежуточном стеке является целочисленным значением. Следующий за ним элемент является указателем на целочисленную переменную.
Вытолкнуть из промежуточного стека два элемента.
Постусловие: Значение целого числа по данному указателю равно данному выражению. | |
__set_rational_variable
|
Предусловие: Верхний элемент в промежуточном стеке является рациональным значением. Следующий за ним элемент является указателем на рациональную переменную.
Вытолкнуть из промежуточного стека два элемента.
Постусловие: Значение рационального числа по данному указателю равно данному выражению. |
Пояснение:__copy_memory– это функция на языке ассемблера, которая выполняет копирование данных. Данная функция принадлежит библиотеке функций и макросов, которая была предварительно написана для более удобной трансляции.
Вызов функции соответствует конвенции вызовов stdcall, принятой вC. По этой конвенции стек очищает тот же, кто кладет в него параметры – в данном случае командаaddesp, 12 – выталкивает из стека три двойных слова.
Более подробное описание некоторых макросов и функций содержится в приложении.
Команда ПОЛИЗ |
Перевод в ассемблер |
Пояснение |
@SUBS |
pop eax mov eax, 1 xor ebx, ebx xor ecx, ecx xor edx, edx
k – 1 раз в порядке от младших индексов к старшим вывести: pop ebx sub ebx, <левая граница типа индекса> push eax imul ebx add ecx, eax pop eax
mov ebx, <диапазон значений индекса> imul ebx
mov eax, ecx mov ebx, <размер индексируемого элемента> imul ebx pop edx add edx, eax push edx |
Предусловие: Верхний элемент является целочисленной константой k, определяющей количество операндов. Далее следуют (k–1) целочисленных значений и указатель на разыменовываемую переменную.
Вытолкнуть из промежуточного стека (k+1) элемент. Итеративно посчитать адрес смещения.
Постусловие: Данные в регистрах eax,ebx,ecx,edxбудут потеряны.
На вершине стека исполнения находится корректный указатель на элемент массива соответствующий индексации. |
Пояснение:
Обозначим за M= <размер индексируемого элемента>, заCi= <указанныйi-ый индекс>, заLi= <левая границаi-го индекса>, заRi= <правая границаi-го индекса>. Тогда,Si= <ширинаi-го индекса> =Ri–Li+ 1.
Например, рассмотрим массив:
var
a : array [1..10, 2..20, 3..40] of integer;
и индексацию к нему:
a[10, 19]
Тогда, каждый элемент, который индексирован по первым двум индексам, сам представляет собой массив типа array[3..40]ofinteger, поэтому
M = sizeof(array[3..40] of integer) = 38 * sizeof(integer) =
= 38 * 4 = 152 (байта)
Указано два индекса, 10 и 19, поэтому C1=10, аC2=19.
Левые и правые границы, соответственно, L1=1,L2=2,R1=10,R2=20.
Отсюда ширины индексов, S1=10,S2=19.
В общем случае, полное смещение в байтах, при индексации по kиндексам вычисляется по формуле:
M * ((C1 – L1) * S2 * S3 * … * SK + (C2 – L2) * S3 * … SK+ …
+ (CK – LK))
Генерируемый код на ассемблере вычисляет эту формулу итеративно при известных параметрах индексов.
Описание перевода арифметических операций.
Команда ПОЛИЗ |
Перевод в ассемблер |
Пояснение |
@ADDINT
|
call __add_integer add esp, 4 |
Предусловие: Верхние два элемента являются целочисленными значениями.
Вытолкнуть из промежуточного стека два элемента. Положить в промежуточный стек результат операции в виде целочисленного значения.
Постусловие: На вершине стека исполнения находится целочисленное значение, соответствующее результату операции. |
@SUBINT
|
call __sub_integer add esp, 4 | |
@MULINT
|
call __mul_integer add esp, 4 | |
@DIVINT |
call _div_integer add esp, 4 | |
@NEGINT |
__negate_integer |
Предусловие: На вершине стека находится элемент, являющийся целочисленным значением.
Вытолкнуть из промежуточного стека элемент. Положить в промежуточный стек результат операции в виде целочисленного значения.
Постусловие: На вершине стека исполнения находится целочисленное значение, соответствующее результату операции. |
@INC |
__increment_integer_variable |
Предусловие: На вершине стека находится элемент, являющийся указателем на целочисленное значение.
Вытолкнуть из промежуточного стека элемент.
Постусловие: Элемент, находящийся по данному указателю, был увеличен на единицу.
|
@DEC |
__decrement_integer_variable |
Предусловие: На вершине стека находится элемент, являющийся указателем на целочисленное значение.
Вытолкнуть из промежуточного стека элемент.
Постусловие: Элемент, находящийся по данному указателю, был уменьшен на единицу. |
Абсолютно аналогично транслируются бинарные операции с рациональными числами @ADDRAT, @SUBRAT, @MULRAT, @DIVRAT, @COMMONи унарные @NEGRAT, @FRAC, @INT, и @SIMPLIFY.
Также транслируются бинарные операции с логическим типом @AND, @ORи унарная @NOT. Логический тип рассматривается как целочисленный, принимающий значения 0 (false) или 1 (true).
Бинарные операции сравнений рациональных и целых чисел @=INT, @=RAT, @>INT, @>RAT, @<INT, @<RAT, @>=INT, @>=RAT, @<=INT, @<=RAT, @<>INT, @<>RATтранслируются аналогично.
Все они принимают в качестве параметров значения и кладут в стек результирующие значения.
Команда ПОЛИЗ |
Перевод в ассемблер |
Пояснение |
@NUMERATOR
|
__numerator_rational_variable
|
Предусловие: Верхний элемент является указателем на рациональное число.
Вытолкнуть из промежуточного стека элемент. Положить в промежуточный стек результат операции в виде указателя на целое число.
Постусловие: На вершине стека исполнения находится указатель, соответствующий результату операции (указатель на числитель или указатель на знаменатель рационального числа). |
@DENOMINATOR
|
__denominator_rational_variable
| |
@ITOR |
__integer_to_rational |
Предусловие: Верхний элемент является целочисленным значением.
Вытолкнуть из промежуточного стека элемент. Положить в промежуточный стек результат операции в виде рационального значения. Постусловие: На вершине стека исполнения находится приведенное рациональное значение. |
@ITOR2 |
pop eax pop ebx (возможное разыменовывание указателя) __integer_to_rational push ebx push eax
|
Предусловие: На вершине стека находится рациональное значение, следующий за ним элемент представляет собой целочисленное значение.
Вытолкнуть из промежуточного стека элемент и сохранить его, изменить тип вершины стека с целочисленного значения на рациональное значение. Положить сохраненный элемент на вершину стека.
Постусловие: первые два элемента стека представляют собой рациональные значения. |
@INPUT |
call __input_integer_variable add esp, 4 |
Предусловие: На вершине стека находится указатель на целое число.
Вытолкнуть из промежуточного стека элемент.
Постусловие: Содержимое памяти по данному указателю соответствует введенному с консоли знаковому целому числу. |
__input_rational_variable |
Предусловие: На вершине стека находится указатель на рациональное число.
Вытолкнуть из промежуточного стека элемент.
Постусловие: Содержимое памяти по данному указателю соответствует двум введенным через enterс консоли знаковым целым числам – числителю и знаменателю рационального числа. |
@OUTPUT |
call __output_integer add esp, 4 |
Предусловие: На вершине стека находится целочисленное значение..
Вытолкнуть из промежуточного стека элемент.
Постусловие: В консоль выведено целое знаковое число. |
call __output_rational add esp, 8 |
Предусловие: На вершине стека находится рациональное значение.
Вытолкнуть из промежуточного стека элемент.
Постусловие: В консоль выведено рациональное число в формате <числитель>/<знаменатель>. |
Замечание:
Когда речь идет о том, что на вершине стека находится рациональное значение – имеются в виду, два двойных слова, записанных последовательно – причем верхушка стека соответствует числителю, а следующий за верхушкой элемент – знаменателю.
Для того чтобы разыменовывать указатели дозначений, используются два макроса__evaluate_rationalи__evaluate_integer. Их код приведен в приложении.