Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Pascal_Unkn.doc
Скачиваний:
8
Добавлен:
03.11.2018
Размер:
1.63 Mб
Скачать

Почему так много процедур?

К этому моменту вы можете подумать, что я зашел слишком далеко в смысле глубоко вложенных процедур. В этом несомненно есть большие накладные расходы. Но в моем безумии есть смысл. Как в случае с UnOp, я заглядываю вперед на время, когда мы захотим генерировать лучший код. С таким способом организации кода мы можем достичь этого без значительных изменений в программе Например, в случаях, где значение, помещенное в стек не должно преобразовываться, все же лучше использовать инструкцию "вытолкнуть и сложить". Если мы решим проверять такие случаи, мы можем включить дополнительные тесты в PopAdd  и  PopSub не изменяя что-либо еще.

Мультипликативные выражения

Процедуры для работы с мультипликативными операторами почти такие же. Фактически, на первом уровне они почти идентичны, так что я просто покажу их здесь без особых фанфар. Первая - наша общая форма для Factor, которая включает подвыражения в скобках:

{---------------------------------------------------------------}

{ Parse and Translate a Factor }

function Expression: char; Forward;

function Factor: char; begin    if Look = '(' then begin       Match('(');       Factor := Expression;       Match(')');       end    else if IsAlpha(Look) then       Factor := Load(GetName)    else       Factor := LoadNum(GetNum); end;

{--------------------------------------------------------------} { Recognize and Translate a Multiply }

Function Multiply(T1: char): char; begin    Match('*');    Multiply := PopMul(T1, Factor); end;

{--------------------------------------------------------------} { Recognize and Translate a Divide }

function Divide(T1: char): char; begin    Match('/');    DIvide := PopDiv(T1, Factor); end;

{---------------------------------------------------------------} { Parse and Translate a Math Term }

function Term: char; var Typ: char; begin    Typ := Factor;    while IsMulop(Look) do begin       Push(Typ);       case Look of        '*': Typ := Multiply(Typ);        '/': Typ := Divide(Typ);       end;    end;    Term := Typ; end;

{---------------------------------------------------------------}

Эти подпрограммы соответствуют аддитивным почти полностью. Как и прежде, сложность изолирована в PopMul и PopDiv. Если вам захочется протестировать программу прежде чем мы займемся ими, вы можете написать их пустые версии, аналогичные PopAdd и PopSub. И снова, код не будет корректным в данный момент, но синтаксический анализатор должен обрабатывать выражения произвольной сложности.

Умножение

Если вы убедились, что сам синтаксический анализатор работает правильно, мы должны выяснить, что необходимо сделать для генерации правильного кода. С этого места дела становятся немного труднее так как правила более сложные.

Давайте с начала возьмем случай умножения. Эта операция аналогична "addops" в том, что оба операнда должны быть одного и того же размера. Она отличается в трех важных отношениях:

  • Тип произведения обычно не такой же как тип двух операндов. Для произведения двух слов мы получаем в результате длинное слово.

  • 68000 не поддерживает умножение 32 x 32, так что необходим вызов подпрограммы для программного умножения.

  • Он также не поддерживает умножение 8 x 8, поэтому байтовые операнды должны быть переведены до слова.

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

T1

T2

B

W

L

B

Преобразовать D0 в W

Преобразовать D7 в W

MULS

Result = W

Преобразовать D0 в W

MULS

Result = L

Преобразовать D0 в L

JSR MUL32

Result = L

W

Преобразовать D7 в W

MULS

Result = L

MULS

Result = L

Преобразовать D0 в L

JSR MUL32

Result = L

L

Преобразовать D7 в L

JSR MUL32

Result = L

Преобразовать D7 в L

JSR MUL32

Result = L

JSR MUL32

Result = L

Эта таблица показывает действия, предпринимаемые для каждой комбинации типов операндов. Есть три вещи, на которые необходимо обратить внимание: во-первых, мы предполагаем, что существует библиотечная подпрограмма MUL32, которая выполняет 32  x  32 умножение, оставляя 32-битное (не 64) произведение.        Если в процессе этого происходит переполнение мы игнорируем его и возвращаем только младшие 32 бита.

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

Теперь ясно, что мы должны будем генерировать различный код для 16-разрядного и 32-разрядного умножения. Для этого лучше всего иметь отдельные подпрограммы генерации кода для этих двух случаев:

{---------------------------------------------------------------}

{ Multiply Top of Stack by Primary (Word) }

procedure GenMult; begin    EmitLn('MULS D7,D0') end;

{---------------------------------------------------------------} { Multiply Top of Stack by Primary (Long) }

procedure GenLongMult; begin    EmitLn('JSR MUL32'); end;

{---------------------------------------------------------------}

Исследование кода ниже для PopMul должно убедить вас, что условия в таблице выполнены:

{---------------------------------------------------------------}

{ Generate Code to Multiply Primary by Stack }

function PopMul(T1, T2: char): char; var T: char; begin    Pop(T1);    T := SameType(T1, T2);    Convert(T, 'W', 'D7');    Convert(T, 'W', 'D0');    if T = 'L' then       GenLongMult    else       GenMult;    if T = 'B' then       PopMul := 'W'    else       PopMul:= 'L'; end;

{---------------------------------------------------------------}

Как вы можете видеть, подпрограмма начинается совсем как PopAdd. Два аргумента приводятся к тому же самому типу. Два вызова Convert заботятся о случаях, когда оба операнда - байты. Сами данные переводятся до слова, но подпрограмма помнит тип чтобы назначать корректный тип результату. В заключение мы вызываем одну из двух подпрограмм генерации кода и затем назначаем тип результата. Не слишком сложно, действительно.

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]