|
|
|
|
Макродиректива повторения - REPT
MASM обеспечивает возможность повторять блок макрокода. Существует три варианта повтора, причем каждый из них имеет свое особое
предназначение.
В качестве первого примера предположим, что мы хотим создать в сегменте данных область для обработки файлов. Для получения доступа к файлам мы
используем метод описателя файла и, так как мы хотим работать более чем с одним файлом, мы пишем программу, присваивая каждому блоку уникальное имя.
file_head MACRO fnum
file_hand_&fnum dw ? ;заголовок файла
file_nmax_&fnum db 49 ;макс.длина имени файла
file_nlen_&fnum db ? ;действит.длина имени файла
file_name_&fnum db 50 dup (?) ;буфер имени файла
ENDM
|
Почему для fnum (номер файла) мы не использовали директиву LOCAL? Потому, что для самого макро эти метки не являются локальными. К ним должен
осуществляться доступ из других частей программы с целью установки имени файла, получения возможности оперирования с блоком управления файлом и т.д.
Это макро может быть усовершенствовано. Что необходимо сообщить программе пофайлового копирования, если мы хотим одновременно обрабатывать два
файла? Нам следует дважды вызвать file_head (описатель файла):
file_head 1 ;1-ый блок файла
file_head 2 ;2-ой блок файла
|
Вместо этого, используя директиву REPT (повторить), мы можем написать file_head так, чтобы он определял столько блоков, сколько необходимо. Такой
макрос приведен в Листинге 1-3.
Листинг 1-3. Описание блока доступа к файлу
------------------------------------------------------------
fcnt = 0 ;определить и иниц-ать символ
file_head2 MACRO fnum
file_hand_&fnum dw ? ;заголовок файла
file_nmax_&fnum db 49 ;макс.длина имени файла
file_nlen_&fnum db ? ;действ.длина имени файла
file_name_&fnum db 50 dup (?) ;буфер имени файла
ENDM
file_head MACRO fnum
REPT fnum ;повторить блок "fnum" раз
file_head2 %fcnt ;создать блок #"fcnt"
fcnt = fcnt + 1
ENDM ;закончить блок повторения
ENDM ;закончить макро file_head
-------------------------------------------------------------
|
Как показано в Листинге 1-4, при вызове макро file_head оно, в свою очередь, дважды вызывает макро file_head2, используя каждый раз новое значение
fnum. Конечно, это макрорасширение со значением статуса листинга, установленного по умолчанию, не показывает явно обращения к file_head2. Однако
результат работы REPT мы можем видеть по двум созданным блокам управления файлами. Заметим, что директива REPT должна заканчиваться строкой ENDM,
равно как и директива MACRO. Вcе блоки повторения должны заканчиваться ENDM (конец макро). Аналогично ENDM должно появляться в конце каждого
макроопределения.
Листинг 1-4. Макрорасширение блока описания доступа к файлу
-----------------------------------------------------------------
file_head 2
3 file_hand_0 dw ? ;заголовок файла
3 file_nmax_0 db 49 ;макс. длина имени файла
3 file_nlen_0 db ? ;действит.длина имени файла
3 file_name_0 db 50 dup (?) ;буфер имени файла
3 file_hand_1 dw ? ;заголовок файла
3 file_nmax_1 db 49 ;макс. длина имени файла
3 file_nlen_1 db ? ;действит.длина имени файла
3 file_name_1 db 50 dup (?) ;буфер имени файла
------------------------------------------------------------------
|
В добавление к директиве REPT мы также использовали счетчик. Счетчик - это переменная, имеющая цифровое значение. Так как его значение может
меняться, он должен быть определен при помощи оператора присваивания (=). (В MASM для определения переменных, имеющих статические значения,
используется оператор equ (приравнять), в то время как для определения переменных, чьи значения могут изменяться, применяется знак равенства
(=).) Счетчик, применяемый в макро file_head, называется fcnt (счетчик файла). Счетчик fcnt увеличивается на 1 при каждом проходе file_head. Но
почему метки находятся в file_head2, file_hand_0 и т.д., а не в file_hand_fcnt? Каким образом имя fcnt заменяется на свое значение? Ответ
заключается в операторе "%",стоящем в вызове file_head2 перед fcnt. Знак процента предписывает замену символа на его значение. Так как мы
использовали знак процента, нам необходимы два макро. Если бы мы попытались вычислить и подставить fcnt в одно маkро:
REPT fnum ;повторить блок "fnum" раз
file_hand_&%fcnt dw ? ;заголовок файла ,
возникла бы ошибка символа:
file_hand_fcnt dw ? ;заголовок файла
|
Оператор процента (%) работает только в аргументах макровызова! Кроме того, значение символа должно быть абсолютной (неперемещаемой)
константой.
Другим важным аспектом наших макро является то, что счетчик fcnt инициализируется вне макроблока. Это делается потому, что мы не хотим устанавливать
fcnt в 0 всякий раз при вызове file_head (что может вызвать дублирование меток). Однако, fcnt должен быть где-то инициализирован, или оператор:
вызовет появление сообщения об ошибке "Символ не определен".
|
|