До сих пор макрокоманды не отличались от подпрограмм с точки зрения
как их функционирования, так и использования параметров. Далее, нам
требуется возмоность ассемблирования в зависимости от условия. Так
же как ход выполнения подпрограммы может меняться в зависимости от
некоторых условицй в момент выполнения, так и у макрокоманды должна
быть возможность изменять в момент транслирования генерацию
соответствующего машинного кода в зависимости от удовлетворения
условий.
Макроассемблер фирмы IBM допускает условное ассемблирование. На
самом деле, условное ассемблирование не обязательно входит только в
макрокоманду. Программа может использовать условное транслирование
в любом месте ассемблерного текста. Однако наиболее часто оно
встречается в макрокомандах. В IBM PC условное транслирование
поддерживается только Макроассемблером MASM.
Так же, как и выполнение макрокоманд, условное ассемблирование
происходит во время трансляции, а не выполнения программы. Условное
транслирование позволяет программисту "запрограммировать" ассемблер
на транслирование различных последовательостей кодов. Ассемблер
определяет, что ему транслировать по параметру, известному во время
ассемблирования. Хотя эта возможность может использоваться
программой в любой момент ассемблирования, мы изучим прежде всего,
как она влияет на ассемблирование макрокоманд.
Фиг. 6.4 иллюстрирует условное транслирование при расширении
макрокоманды FIDIVR сопроцессора 8087. Условное тарнслирование
требуетя данной макрокоманде из-за разделения переменных в
ассемблере по типам. Как мы увидим в гл.7, команда, обозначенная
FIDIVR, может применяться к операндам двух типов. Операнд может
быть двух- или четырехбайтовым целым числом. Мы хотим, чтобы
ассемблер выбрал правильный машинный код в зависимости от типа
операнда. Как мы вмдели, у команды ADD в действительности имеется
несколько форм, в зависимости от того, какие операнды представлены
ассемблеру, который выбирает верную форму машинной команды в
зависиммости от этих операндов. Мы хотим делать то же самое для
команды FIDIVR Но в теперь макропроцессор должен определить тип
операнда и сгенерировать правильную команду.
У команды FIDIVR может быть один из двух типов операндов, и в
зависимости от этого будут различаться результирующие команды.
Таким образом, расширение макрокоманды FIDIVR должно
соответствовать нужному операнду. Это обеспечивается двумя
средствами языка: условным транслированием и оператором TYPE.
В языке ассемблера имеется оператор TYPE, который возвращает
Microsoft (R) Macro Assembler Version 5.00 4/2/89 16:06:42
Фиг. 6.4 Условное транслирование Page 1-1
PAGE ,132
TITLE Фиг. 6.4 Условное транслирование
FIDIVR MACRO SOURCE
IFE 2 - TYPE SOURCE
DB 09BH ;; FWAIT
ESC 037H,SOURCE ;; FIDIVR слово
ENDIF
IFE 4 - TYPE SOURCE
DB 09BH ;; FWAIT
ESC 017H,SOURCE ;; FIDIVR короткое целое
ENDIF
ENDM
0000 CODE SEGMENT
ASSUME CS:CODE,DS:CODE
0000 ???? TWO_BYTE DW ?
0002 ???????? FOUR_BYTE DD ?
0006 ?? ONE_BYTE DB ?
FIDIVR TWO_BYTE
0007 9B 1 DB 09BH ;
0008 DE 3E 0000 R 1 ESC 037H,TWO_BYTE ;
FIDIVR FOUR_BYTE
000C 9B 1 DB 09BH ;
000D DA 3E 0002 R 1 ESC 017H,FOUR_BYTE ;
FIDIVR ONE_BYTE
0011 CODE ENDS
END
Фиг. 6.4. Ассемблирование макрокоманд по условию
значение, равное длине операнда. В случае FIDIVR мы ожидаем, что
операнд будет двух- или четырехбайтовым целым числом.
Выражение
IFE 2-TYPE SOURCE
в макрокоманде FIDIVR проверяет длину операнда SOURCE.
Арифметическое выражение 2=TYPE SOURCE, равняется 0, если операнд
SOURCE является двухбайтовым целым числом, и принимает ненулевое
значение при любом другом типе операнда. Оператор IFE
(транслировать, если равно) сообщает ассемблеру, что нужно
транслировать все последующие команды, если выражение в поле
операнда равно 0. Таким образом, оператор IFE вырабатывает значение
истина, если операнд SOURCE является двухбайтовым целым числом. В
этом случае происходит трансляция всех команд, следующих за
оператором IFE до тех пор, пока не встретится оператор ENDIF. В
нашем примере это означает, что если операнд является двухбайтовым
целым числом, то ассемблируется участок программы
DB 09BH
ESC 37H,SOURCE
В первом вызове макрокоманды на Фиг. 6.4 в качестве операнда
используется двухбайтовое целое число. Поэтому, для расширения этой
макрокоманды ассемблер выбирает команду ESC 37H.
Так как команда FIDIVR имеет два варианта, соответствующие двум
разным типам операндов, то в при выполнении другого условия,
макрокоманда использует второй оператор IFE. Когда операнд является
четырехбайтовым целым числом, макрокоманда генерирует код ESC 17H.
На Фиг. 6.4 показаны два разных расширения одной макрокоманды.
Обратите внимание, что в последнем из показанных на Фиг. 6.4
вызовов макрокоманды операнд не удовлетворяет ни одному из условий.
Так как ни один из операторов IFE не вырабатывает значения
"истина", то и ассемблироваться не будет ни один из них. В этом
случае макропроцессор не генерирует никакого кода.
С помощью оператора IFE ассемблер может проверять выполнение
различных условий. Эти условия приведены в таблице на Фиг. 6.5.
Общая форма оператора IF имеет вид:
IFхх выражение
...
ELSE
...
ENDIF
Если значение условия "истина", то ассемблер обрабатывает
участок программы, следующий за оператором IFхх. Этот транслируемый
участок программы заканчивается либо оператором ELSE или ENDIF.
Оператор ELSE не является обязательным. Если он имеется, то
следующий за ним участок программы будет транслирован при
невыполнении условия в операторе IF. Оператор ENDIF завершает
условное ассемблирование и является обязательным.
IF-операция Ассемблировать если:
---------------------------------------------------------------
IF выражение Выражение не равно 0
IFE выражение Выражение равно 0
IFDEF имя Имя уже было описано как внешнее
IFNDEF имя Имя еще не описывалось
IFB <аргумент> Аргумент пуст
IFNB <аргумент> Аргумент не пуст
IFIDN <арг1>,<арг2> Строка арг1 идентична строке арг2
IFDIF <арг1>,<арг2> Строка арг1 отличается от строки арг2
IF1 Первый поход ассемблера
IF2 Второй проход ассемблера
---------------------------------------------------------------
Фиг. 6.5 Операторы IF для условного ассемблирования
Рассмотрим еще один пример, чтобы познакомиться с некоторыми
другими вариантами использования ассемблирования по условию. На
Фиг. 6.6 показано применение другого условного оператора - IFB, а
также использование вложенных условных операторов. Макрокомандой
здесь является FLD - команда загрузки сопроцессора 8087. Для
транслирования этой команды требуется несколько условных
операторов, так как она может применяться в следующих вариантах:
FLD
FLD 1
FLD короткое_вещественное
FLD длинное_вещественное
FLD временное_вещественное
Поле операнда макрокоманды FLD может быть пустым, содержать
константу, или четырехбайтовую, восьмибайтовую либо десятибайтовую
переменную. Макрокоманда должна распознать каждый из перечисленныз
случаев и сгенерировать правильный программный код. (все эти типы
данных рассмотрены очень подробно в гл.7.)
Оператор IFB проверяет наличие операнда. Если операнд
отсутствует, то ассемблер генерирует соответствующий этому случаю
программный код, так как оператор IFB вырабатывает значение
"истина". Это иллюстрирует первый вызов макрокоманды, когда
генерируется код
DB 09BH,0D9H,0C 1H
Оператор EXITM, содержащийся в этой части условного оператора
IF, реализует выход из макрокоманды. Каждый раз, когда при
расширении макрокоманды ассемблеру встречается этот оператор,
расширение заканчивается, как если бы встретился ENDM. В данном
случае ассемблер пропускает оставшуюся часть макроопределения. При
таком выходе из макрокоманды в ассемблерном листинге появляется
предупреждающее сообщение "Open conditionals:1" ("Незавершенные
условные операторы: 1"). Оно предупреждает вас, что ассемблер не Mincho"'> Microsoft (R) Macro Assembler Version 5.00 4/2/89 16:06:47
Фиг. 6.6 Вложенные условные макрокоманды Page 1-1
PAGE ,132
TITLE Фиг. 6.6 Вложенные условные макрокоманды
FLD MACRO SOURCE
IFB <SOURCE>
DB 09BH,0D9H,0C1H ;; FLD ST(1)
EXITM
ELSE
IFE TYPE SOURCE
DB 09BH,0D9H,0C0H+SOURCE
;; FLD ST(i)
ENDIF
IFE 4 - TYPE SOURCE
DB 09BH
ESC 8,SOURCE ;; FLD короткое плавающее
ENDIF
IFE 8 - TYPE SOURCE
DB 09BH
ESC 40,SOURCE ;; FLD длинное плавающее
ENDIF
IFE 4 - TYPE SOURCE
DB 09BH
ESC 01DH,SOURCE ;; FLD временное плавающее
ENDIF
ENDIF
ENDM
0000 CODE SEGMENT
ASSUME CS:CODE,DS:CODE
0000 ???????? FOUR_BYTE DD ?
0004 ???????????????? EIGHT_BYTE DQ ?
000C ??????????????????? TEN_BYTE DT ?
?
FLD
0016 9B D9 C1 1 DB 09BH,0D9H,0C1H ;
FLD 1
0019 9B D9 C1 1 DB 09BH,0D9H,0C0H+1
FLD FOUR_BYTE
001C 9B 1 DB 09BH
001D D9 06 0000 R 1 ESC 8,FOUR_BYTE ;
0021 9B 1 DB 09BH
0022 DB 2E 0000 R 1 ESC 01DH,FOUR_BYTE ;
FLD EIGHT_BYTE
0026 9B 1 DB 09BH
0027 DD 06 0004 R 1 ESC 40,EIGHT_BYTE ;
FLD TEN_BYTE
002B CODE ENDS
END
Фиг. 6.6 Вложенное условное ассемблирование
встретил оператора ENDIF, закрывающего условный оператор. Это
происходит в результате раннего входа из макрокоманды. Хотя это и
нежелательно, но ни к каким разрушительным последствиям не
приводит. Если оператор EXITM расположен вне условного оператора,
то предупреждение не выводится.
Оператор EXITM необходим в данной макрокоманде, так как
ассемблер проверяет все условные операторы, даже если они не
транслируются. В нашем случае, если операнд SOURCE пуст, оператор
ELSE предотвращает генерацию всех других вариантов команды FLD.
Однако, продолжая просмотр, ассемблер проверяет оператора
IFE TYPE SOURCE
хотя и не может сгенерировать никакого кода. Если SOURCE пусто,
то ассемблер фиксирует синтаксическую ошибку. Вы можете не обращать
внимания на эту ошибку, но принимать трансляцию с сообщениями об
ошибках идет в разрез с нашими правилами. С другой стороны,
использование оператора EXITM приводит к предупреждению "Открытое
условие". Оно нежелательно, но это меньшее из двух зол.
Заметим, что макрокоманда FLD использует ветвь ELSE чтобы
указать на необходимость вычисления выражения в поле операнда
только в случае непустоты этого поля. IF-выражения, содержащие
оператор TYPE, определяют, какой тип операнда использовался при
вызове макрокоманды. Хотя это не упоминается в Руководстве по
Макроассемблеру, оператор TYPE возвращает значение 0, если операнд
является не символическим именем, а константой. Выбор такого
способа в данной макрокоманде вызван скорее соображениями
работоспособности, чем стремлением к элегантности.