|
|
|
|
Макро, вызывающее подпрограммы
Одно из наиболее мощных применений макро заключается в универсальном вызове подпрограмм аналогично вызовам подпрограмм в языках высокого уровня.
Задача заключается в проталкивании нескольких параметров в стек и вызове подпрограммы. Довольно просто, за исключением потребности макро приспособиться
к переменному числу параметров, которые в свою очередь могут иметь переменные размеры (байт,слово, двойное слово, четвертное слово и 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, однако рассмотрение общецелевой функции вызова подпрограмм требует нечто большего. Прежде чем продолжить разбор этого макро
мы сделаем короткое отвлечение на введение понятия структуры.
|
|