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










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

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

Макро, вызывающее подпрограммы

Одно из наиболее мощных применений макро заключается в универсальном вызове подпрограмм аналогично вызовам подпрограмм в языках высокого уровня. Задача заключается в проталкивании нескольких параметров в стек и вызове подпрограммы. Довольно просто, за исключением потребности макро приспособиться к переменному числу параметров, которые в свою очередь могут иметь переменные размеры (байт,слово, двойное слово, четвертное слово и 10-байтовые значения с плавающей точкой). Для выполнения этих требований мы используем операторы .TYPE и TYPE (обратите внимание на точку перед первым оператором). Использование оператора .TYPE позволяет макро поддерживать как регистр типа BX, так и слово или байт данных. Конструкция .TYPE х возвращает байт, набор битов которого содержит следующую информацию:



            БИТ 0 = 1, если х программно зависимо, иначе = 0
            БИТ 1 = 1, если х зависимо от данных, иначе  = 0
            БИТ 5 = 1, если х определено, иначе          = 0
            БИТ 7 = 1, если х - внешний параметр, если локальный
                                    или общий            = 0

Все остальные биты нулевые.

Например, если х зависимо от данных, определено и локально, оператор.TYPE х возвращает значение 001000100b (или 22h); -- установлены биты 1 и 5. Так как мы хотим разрешить использование регистров (программно зависимых) в качестве параметров, мы будем применять оператор .TYPE для сообщения о наличии параметров, зависящих от данных. Так как мы хотим поддерживать данные различной длины отдельно, мы используем оператор TYPE, возвращающий длину их аргументов в байтах. Например,



            TYPE N =  1, если N  - байт
            TYPE N =  2, ecли N  - слово
            TYPE N =  4, ecли N  - двойное слово
            TYPE N =  8, если N  - четверное слово
            TYPE N = 10, если N  - десятибайтовое слово (т.е. с плаваю-
                                   щей  точкой)
            TYPE N = XX, если N  - cтруктура длиной в хх байтов
            TYPE N = FFFF,если N - "близкая" программная метка
            TYPE N = FFFE,если N - "удаленная" программная метка

Следующее макро иллюстрирует использование директив TYPE и .TYPE:



            @FcnCall MACRO  Fnctn,ParmList  ;;список подпро-мм и парам-ов
                   IRP     N,    ;;неопределен. повторение
                   BYTELENGTH = TYPE N      ;;получить длину "проталкива-
                              ;;емых" элементов в байтах
                     IF ((.TYPE N ) NE  22H)     ;;N определено и зави-
                                                 ;;симо от данных?
                     push  N ;;если нет - предположить 16-битовый регистр
                     ELSE    ;;в противном случае предположить данные
                       IF (BYTELENGTH EQ 2) ;;тогда, если параметр 2-
                                            ;;байтовый,
                     push N      ;;протолкнуть
                     ELSE        ;;в противном случае
                       IF (BYTELENGTH EQ 1)  ;;если параметр 1-байтовый,
                                  ;;предположить, что AX доступен
                       mov      ah,0  ;;очистить верхнюю часть AX
                       mov      al,N  ;;сделать  параметр словом
                       push     ax  ;;так, чтобы мы могли продвинуть его
                       ELSE         ;;в противном случае
                         IF (BYTELENGTH EQ 4) ;;если параметр 4-байтовый
                         push    word ptr N     ;;продвинуть 1-ое и
                         push    word ptr N + 2  ;;2-ое слово
                         ELSE      ;;в противном случае
                           IF (BYTELENGTH EQ 8) ;;если параметр 8-байт.
                           push  word ptr N     ;;продвинуть 1-ое,
                           push  word ptr N + 2   ;;  2-ое
                           push  word ptr N + 4   ;;  3-ье и
                           push  word ptr N + 6   ;;  4-ое слово
                           ELSE         ;;в противном случае
                             IF  (BYTELENGTH EQ  10)   ;;если параметр
                                             ;;10-байтовый, продвинуть
                             push word ptr N   ;; 1-ое
                             push word ptr N + 2       ;; 2-ое
                             push word ptr N + 4       ;; 3-ье
                             push word ptr N + 6       ;; 4-ое  и
                             push word ptr N + 8       ;; 5-ое слово
                             ELSE
                             .ERR
                             ENDIF
                           ENDIF
                         ENDIF
                       ENDIF
                     ENDIF
                   ENDIF
                 call Fnctn
                 ENDM                               ;;конец IRP
                 ENDM                               ;;конец макро

Замечательным преимуществом данного макро является то, что мы заранее не указываем количество параметров, которое хотим переслать подпрограмме, до непосредственного обращения к ней. Мы можем вызвать одну подпрограмму с тремя параметрами, а другую - с двумя. Например:



            @FcnCall Fcn1,
            @FcnCall Fcn2,

Для любого вызова подпрограммы мы можем иметь фактически неограниченное число параметров.


В данном макро имеется много недостатков. Одним из этих недостатков является то, что мы не покрыли все возможные значения BYTELENGTH, типа программных меток и структур; мы предположили, что регистр AX доступен только для однобайтового параметра и т.д. Для большинства этих недостатков существует дилемма: цикл, на базе BYTELENGTH, мог бы поддерживать все возможные длины данных, но при этом могли возникнуть другие проблемы, поэтому мы даже не рассматриваем альтернативы, а считаем своей задачей лишь "проталкивание" данных в вызываемую подпрограмму! Пример служит для иллюстрации директив TYPE и .TYPE, однако рассмотрение общецелевой функции вызова подпрограмм требует нечто большего. Прежде чем продолжить разбор этого макро мы сделаем короткое отвлечение на введение понятия структуры.


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

Hosted by uCoz