IFB <аргумент> Если аргументом является пробел, ассемблер
обрабатывает операторы в условном блоке. Аргумент
должен быть в угловых скобках.
IFNB <аргумент> Если аргументом является не пробел, то ассемблер
обрабатывает операторы в условном блоке. Аргумент
должен быть в угловых скобках.
IFIDN <арг-1>,<арг-2> Если строка первого аргумента идентична строке
второго аргумента, то ассемблер обрабатывает
операторы в условном блоке. Аргументы должны быть
в угловых скобках.
IFDIF<арг-1>,<арг-2> Если строка первого аргумента отличается от
строки второго аргумента, то ассемблер
обрабатывает операторы в условном блоке.
Аргументы должны быть в угловых скобках.
Ниже приведен простой пример директивы IFNB (если не пробел). Для DOS
INT 21H все запросы требуют занесения номера функции в регистр AH, в то
время как лишь некоторые из них используют значение в регистре DX.
Следующее макроопределение учитывает эту особенность:
DOS21 MACRO DOSFUNC,DXADDRES
MOV AN,DOSFUNC
IFNB
MOV DX,OFFSET DXADDRES
ENDIF
INT 21H
ENDM
Использование DOS21 для простого ввода с клавиатуры требует установки
значения 01 в регистр AH:
DOS21 01
Ассемблер генерирует в результате команды MOV AH,01 и INT 21H. Для ввода
символьной строки требуется занести в регистр AH значение 0AH, а в регистр
DX - адрес области ввода:
DOS21 0AH,IPFIELD
Ассемблер генерирует в результате обе команды MOV и INT 21H.
ДИРЕКТИВА ВЫХОДА ИЗ МАКРОСА EXITM.
________________________________________________________________
Макроопределение может содержать условные директивы, которые
проверяют важные условия. Если условие истинно, то ассемблер должен
прекратить дальнейшее макрорасширение. Для этой цели служит директива
EXITM:
IFxx [условие]
.
. (неправильное условие)
.
EXITM
.
.
ENDIF
Как только ассемблер попадает в процессе генерации макрорасширения на
директиву EXITM, дальнейшее расширение прекращается и обработка
продолжается после директивы ENDM. Можно использовать EXITM для
прекращения повторений по директивам REPT, IRP и IRPC даже если они
находятся внутри макроопределения.
МАКРОКОМАНДЫ, ИСПОЛЬЗУЮЩИЕ IF И IFNDEF УСЛОВИЯ
________________________________________________________________
Программа на рис.20.6 содержит макроопределение DIVIDE, которая
генерирует подпрограмму для выполнения деления вычитанием. Макрокоманда
должна кодироваться с параметрами в следующей последовательности: делимое,
делитель, частное. Макрокоманда содержит директиву IFNDEF для проверки
наличия параметров. Для любого неопределенного элемента макрокоманда
увеличивает счетчик CNTR. Этот счетчик может иметь любое корректное имя и
предназначен для временного использования в макроопределении. После
проверки всех трех параметров, макрокоманда проверяет CNTR:
IF CNTR
;Макрорасширение прекращено
EXITM
Если счетчик CNTR содержит ненулевое значение, то ассемблер
генерирует комментарий и прекращает по директиве EXITM дальнейшее
макрорасширение. Заметим, что начальная команда устанавливает в счетчике
CNTR нулевое значение и, кроме того, блоки IFNDEF могут устанавливать в
CNTR единичное значение, а не увеличивать его на 1.
Если ассемблер успешно проходит все проверки, то он генерирует
макрорасширение. В кодовом сегменте первая макрокоманда DIVIDE содержит
правильные делимое и частное и, поэтому генерирует только комментарии.
Один из способов улучшения рассматриваемой макрокоманды - обеспечить
проверку на ненулевой делитель и на одинаковый знак делимого и делителя;
для этих целей лучше использовать коды ассемблера, чем условные директивы.
__________________________________________________________________________
TITLE MACRO6 (COM) Проверка директ. IF и IFNDEF
; -----------------------------------------------
DIVIDE MACRO DIVIDEND,DIVISOR,QUOTIENT
LOCAL COMP
LOCAL OUT
CNTR = 0
; AX-делимое, BX-делитель, CX-частное
IFNDEF DIVIDEND
; Делитель не определен
CNTR = CNTR +1
ENDIF
IFNDEF DIVISOR
; Делимое не определено
CNTR = CNTR +1
ENDIF
IFNDEF QUOTIENT
; Частное не определено
CNTR = CNTR +1
ENDIF
IF CNTR
; Макрорасширение отменено
EXITM
ENDIF
MOV AX,DIVIDEND ;Загрузка делимого
MOV BX,DIVISOR ;Загрузка делителя
SUB CX,CX ;Регистр для частного
COMP:
CMP AX,BX ;Делимое < делителя?
JB OUT ; да - выйти
SUB AX,BX ;Делимое - делитель
INC CX ;Частное + 1
JMP COMP
OUT:
MOV QUOTIENT,CX ;Запись результата
ENDM
; -----------------------------------------------
0000 CSEG SEGMENT PARA 'Code'
ASSUME CS:CSEG,DS:CSEG,SS:CSEG,ES:CSEG
0100 ORG 100H
0100 EB 06 BEGIN: JMP SHORT MAIN
; -----------------------------------------------
0102 0096 DIVDND DW 150
0104 001B DIVSOR DW 27
0106 ???? QUOTNT DW ?
; -----------------------------------------------
0108 MAIN PROC NEAR
.LALL
DIVIDE DIVDND,DIVSOR,QUOTNT
= 0000 + CNTR = 0
+ ; AX-делимое, BX-делитель, CX-частное
+ ENDIF
+ ENDIF
+ ENDIF
+ ENDIF
0108 A1 0102 R + MOV AX,DIVDND ;Загрузка делимого
0108 8B 1E 0104 R + MOV BX,DIVSOR ;Загрузка делителя
010F 2B C9 + SUB CX,CX ;Регистр для частного
0111 + ??0000:
0111 3B C3 + CMP AX,BX ;Делимое < делителя?
0113 72 05 + JB ??0001 ; да - выйти
0115 2B C3 + SUB AX,BX ;Делимое - делитель
0117 41 + INC CX
0118 EB F7 + JMP ??0000
011A + ??0001:
011A 89 0E 0106 R + MOV QUOTNT,CX ;Запись результата
DIVIDE DIDND,DIVSOR,QUOT
= 0000 + CNTR = 0
+ ; AX-делимое, BX-делитель, CX-частное
+ IFNDEF DIDND
+ ; Делитель не определен
= 0001 + CNTR = CNTR +1
+ ENDIF
+ ENDIF
+ IFNDEF QUOT
+ ; Частное не определено
= 0002 + CNTR = CNTR +1
+ ENDIF
+ IF CNTR
+ ; Макрорасширение отменено
+ EXITM
011E C3 RET
011F MAIN ENDP
011F CSEG ENDS
END BEGIN
__________________________________________________________________________
Рис.20.6. Использование директив IF и IFNDEF.
МАКРОС, ИСПОЛЬЗУЮЩИЙ IFIDN-УСЛОВИЕ
________________________________________________________________
Программа на рис.20.7 содержит макроопределение по имени MOVIF,
которая генерирует команды MOVSB или MOVSW в зависимости от указанного
параметра. Макрокоманду можно кодировать с параметром B (для байта) или W
(для слова) для генерации команд MOVSB или MOVSW из MOVS.
Обратите внимание на первые два оператора в макроопределении:
MOVIF MACRO TAG
IFIDN <&TAG>,
Условная директива IFIDN сравнивает заданный параметр (предположительно B
или W) со строкой B. Если значения идентичны, то ассемблер генерирует REP
MOVSB. Обычное использование амперсанда (&) - для конкатенации, но в
данном примере операнд без амперсанда не будет работать. Если в
макрокоманде не будет указан параметр B или W, то ассемблер сгенерирует
предупреждающий комментарий и команду MOVSB (по умолчанию).
Примеры в кодовом сегменте трижды проверяют макрокоманду MOVIF: для
параметра B, для параметра W и для неправильного параметра. Не следует
делать попыток выполнения данной программы в том виде, как она приведена
на рисунке, так как регистры CX и DX не обеспечены правильными значениями.
Предполагается, что рассматриваемая макрокоманда не является очень
полезной и ее назначение здесь - проиллюстрировать условные директивы в
простой форме. К данному моменту, однако, вы имеете достаточно информации
для составления больших полезных макроопределений.
__________________________________________________________________________
TITLE MACRO7 (COM) Проверка директивы IFIDN
; -------------------------------------------
MOVIF MACRO TAG
IFIDN <&TAG>,
REP MOVSB
EXITM
ENDIF
IFIDN <&TAG>,
REP MOVSW
ELSE
; Не указан параметр B или W,
; по умолчанию принято B
REP MOVSB
ENDIF
ENDM
; -------------------------------------------
0000 CSIG SEGMENT PARA 'Code'