На главную
Подписка
Новости










Главная / MS-DOS / MS-DOS. РУКОВОДСТВО РАЗРАБОТЧИКА / Глава 1 / Макродиректива повторения - REPT Сделать домашней страницей Добавить в избранное Написать писмо

НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Макродиректива повторения - 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 должен быть где-то инициализирован, или оператор:


           fcnt       =           fcnt +  1

вызовет появление сообщения об ошибке "Символ не определен".


НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Hosted by uCoz