1 je ??0000
3 jmp ?if_100
1 ??0000:
; выполнить, если условие (а) истинно
@IfTrue e условие (b)
1 je ??0001
3 jmp ?if_110
- 1-42 -
1 ??0001:
; выполнить, если условие (b) истинно
@IfElse "else" для условия (b)
3 jmp ?if_111
3 ?if_110:
; выполнить, если условие (b) не истинно
@IfEnd конец условия (b)
3 ?if_111:
@IfElse "else" для условия (a)
3 jmp ?if_101
3 ?if_100:
; выполнить, если условие (а) не истинно
@IfTrue e условие (c)
1 je ??0002
3 jmp ?if_112
1 ??0002:
; выполнить, если условие (с) истинно
@IfElse "else" для условия (c)
3 jmp ?if_113
3 ?if_112:
; выполнить, если условие (с) не истинно
@IfEnd конец условия (c)
3 ?if_113:
@IfEnd конец условия (a)
3 ?if_101:
---------------------------------------------------------------
Листинг 1-16. Расширение структурированных макросов
----------------------------------------------------------------
@IfTrue e
1 je ??0000
3 jmp ?if_100
1 ??0000:
; Выполнить, если истина
@IfElse
3 jmp ?if_101
3 ?if_100:
; Выполнить, если не истина
@IfEnd
3 ?if_101:
;- - - - - - - - - - - - - - - - - - - - - - - - - -
@DoWhile ax,le,bx
3 ?do_100:
1 cmp ax,bx
1 jle ??0001
3 jmp ?do_101
1 ??0001:
; Выполнять пока ax <= bx
@DoExit
3 jmp ?do_101
; Выйти из программы
@DoEnd
3 jmp ?do_100
3 ?do_101:
;- - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 1-43 -
@Repeat
3 ?rep_100:
; Выполнять пока соблюдается условие
@Until ax,e,bx
1 cmp ax,bx
1 je ??0002
3 jmp ?rep_100
1 ??0002:
;- - - - - - - - - - - - -- - - - - - - - - - - - - - -
@For ax,10,20,+
1 mov ax,10 ;инициализировать счетчик
1 jmp ??0003 ;начать цикл FOR
3 ?for_100:
1 inc ax ;увеличить счетчик
1 ??0003: ;проверить на необходимость продолжения
1 cmp ax,20 ;достигнут ли конец
1 jl ??0004 ;нет - продолжить цикл
3 jmp ?for_101
1 ??0004:
; Выполнить для ах = 10 до 20 с шагом 2
@ForEnd
3 jmp ?for_100
3 ?for_101:
----------------------------------------------------------------
Макро псевдо-CASE
Последнее макро, которое мы ввели в этой главе,есть макро
псевдо-case, представленное Листингом 1-17. Так как макро должно
иметь "предвидение" о поддерживаемых в нем структурах, мы не бу-
дем рассматривать его как оператор структурного управления. По
своим функциям макро case более походит на блок диспетчеризации,
типа вычисляемого оператора GOTO в языке Фортран.
Листинг 1-17. Описание макро псевдо-саse
----------------------------------------------------------------
@Case MACRO кey,сase_list,jmр_labels
??tmp_1 = 0
IRP match,<&case_list> ;;последователь-
;;ность вариантов
??tmp_1= ??tmp_1 + 1 ;;установить номер
;;индекса
cmp key,&&match ;вариант найден?
??tmp_2= 0
IRP retl,<&jmp_labels> ;;последователь-
;;ность переходов
??tmp_2=0 = ??tmp_2 + 1 ;; до достижения
;; индекса
IF (??tmp_1 EQ ??tmp_2)
je &&&retl ; Да!
EXITM
ENDIF ;;конец проверки условия
ENDM ;;закончить 2-ой блок IRP
ENDM ;;закончить 1-ый блок IRP
ENDM ;;закончить макроописание
---------------------------------------------------------------
- 1-44 -
Это макро являет собой хороший пример одновременного синтаксичес-
кого анализа двух списков. Внешний цикл, irp match,<&case_list>,
устанавливает последовательность элементов списка вариантов, а
внутренний цикл, irp retl,<&jmp_labels>, выбирает соответствующие
метки переходов.Такое решение может быть использовано для реали-
зации макросов подстановки.
В макросах подстановки внешний цикл устанавливает последова-
тельность элементов списка и выявляет совпадение. После определе-
ния совпадения, скажем на элементе xth, макро входит во внутрен-
ний цикл и устанавливает последовательность элемента xth этого
списка. Одним из возможных вариантов реализации может быть созда-
ние макро переход_по_невыполнению_условия, где выбранный переход
должен был бы заменяться на противоположный. Еще раз напомним,
что во вложенных макроблоках необходимо использовать дополнитель-
ные амперсанды.
Расширение макро @Case представлено в Листинге 1-18. За то,
чтобы в каждом списке появлялся один и тот же номер элемента, от-
вечает программист. В противном случае может быть получена невер-
ная структура управления.
Листинг 1-18. Расширение макро псевдо-@Case
----------------------------------------------------------------
@Case al,<'A','B','C','D'>,
2 cmp al,'A' ;вариант соответствует?
3 je subA ; да!
2 cmp al,'B' ;вариант соответствует?
3 je subB ; да!
2 cmp al,'C' ;вариант соответствует?
3 je subC ; да!
2 cmp al,'D' ;вариант соответствует?
3 je subD ; да!
subA:
jmp merge
subB:
jmp merge
subC:
jmp merge
subD:
jmp merge
default:
merge:
----------------------------------------------------------------
Макросы данных
Макросы могут использоваться для генерации данных или прог-
раммного кода. В обоих случаях подход и методы одинаковы, однако,
в целях изучения рассмотрим макросы, генерирующие только данные.
Простейшим примером команды MASM, генерирующей данные, являет-
ся:
- 1-45 -
TenBytes DB 10 DUP 4 ;зарезервировать 10
;байтов под номером 4
Эта команда имеет ограниченное применение, так как она пред-
почтительна, когда мы хотим получить последовательность чисел как
в индексном наборе. В качестве примера зарезервируем N слов дан-
ных в наборе чисел от 1 до N:
@FirstTry MACRO N ;;определить макро с параметром N
NUMB = 0 ;;инициализировать число
REPT N ;;повторить нижеследующее N раз
NUMB = NUMB+1 ;; увеличить индекс
DW NUMB ;;определить слово NUMB
ENDM ;;закончить команду REPT
ENDM ;;конец макро
Заметим, что для каждой директивы MACRO должно присутствовать
ENDM. Первой переменной, NUMB, значение присваивается оператором
=, а не EQU, что позволяет изменять ее значение в блоке REPT.
Директива REPT представляет собой циклическую структуру, типа
do...while языка высокого уровня. Она повторяет действия, заклю-
ченные между REPT и ENDM, N раз. В данном случае происходит уве-
личение NUMB на 1, а затем создается слово, содержащее это число.
(Имейте в виду, что Вы указываете MASM на создание констант, ко-
торые будут ассемблироваться. Вы не указываете компьютеру цикл,
подлежащий проходу во время выполнения программы)
Если макроописание FirstTry поместить в начало нашей програм-
мы, а затем использовать его в сегменте данных с N, равным 4, мы
получим:
@FirstTry 4
что соответствует тому, что MASM будет ассемблировать четыре сло-
ва чисел от 1 до 4.
Это слишком простой пример использования макро. Разрешите ус-
ложнить его, создав таблицу двоично-десятичных чисел, которая мо-
жет служить таблицей просмотра при преобразовании шестнадцатирич-
ных данных в код BCD.
@BCDtable MACRO N ;;определить макро с параметром N
NUMB = 0 ;;инициализировать числа
HIGHBYTE = 0
REPT N ;;повторить нижеследующее N раз
NUMB = NUMB+1 ;;увеличить индекс
IF (NUMB GT 9)
NUMB = 0
HIGHBYTE = HIGHBYTE + 10H
ENDIF
IF (HIGHBYTE GT 90H)
EXITM
ENDIF
BCDNUMB = (NUMB OR HIGHBYTE)
DW BCDNUMB ;;определить слово с именем NUMB
ENDM ;; конец команды REPT
ENDM ;; конец макро
- 1-46 -
Этот пример значительно сложнее, но он не представляет ничего
особенного для опытного программиста. Прежде чем провести пост-
рочный анализ этих директив (термин "директива" мы используем для
обозначения того, что является командой для MASM, а не для ЦП),
разрешите рассмотреть результат работы программы с N, установлен-
ным в 20:
38 @BCDtable 20