Читать «Assembler. Программирование на языке ассемблера IBM PC» онлайн - страница 140
Unknown Author
Предположим, что имеется процедура NOD, вычисляющая наибольший общий делитель двух чисел: Z=NOD(X,Y), и что параметр X передается ее через регистр АХ, параметр Y - через ВХ, а результат Z возвращается через АХ. И пусть надо вычислить CX=NOD(A,B)+NOD(C,D). Тогда фрагмент программы, реализующий это вычисление, выглядит так:
MOV АХ,А
MOV вх,в
CALL NOD MOV СХ,АХ MOV АХ,С MOV BX,D CALL NOD ADD CX,AX
Легко заметить, что при каждом обращении к процедуре приходится выписывать фактически одну и ту же группу команд. Так, вот, чтобы их не выписывать каждый раз заново, можно эту группу команд описать как макрос, а затем его и использовать. Описание этого макроса выглядит так:
CALLl-NOD macro x,y
MOV AX,X MOV BX, Y CALL NOD ENDM
а нужный нам фрагмент программы:
CALL-NOD а,в
MOV СХ, АХ CALL-NOD C,D ADD СХ,АХ
Как видно, получилось более наглядно и короче. После же макроподстановок получится тот же текст программы, что и прежде, но построением такого текста будет заниматься уже макрогенератор, а не мы.
Отметим попутно, что именно по этому принципу построены операции ввода-вывода, которыми мы пользуемся в данной книге. Например, C4TNT - это на самом деле макрос, описывающий обращение к процедуре, которая и реализует собственно ввод числа. (Описание этих макросов и процедур будет дано в гл. 13.)
При входе в процедуру, как правило, требуется спасать в стеке содержимое регистров, для чего приходится выписывать несколько команд PUSH. И если в программе много процедур, если такая группа команд встречается многократно, то имеет смысл описать ее в виде макроса. Рассмотрим, как выглядит такой макрос.
Прежде всего отметим, что по смыслу у этого макроса может быть любое число фактических параметров (разное число названий регистров). Поскольку в ЯА можно определять макросы только с фиксированным числом формальных параметров, то в подобных ситуациях обычно поступают так: макрос описывают с одним формальным параметром, но при обращении к нему (в макрокоманде) указывают через запятую нужное число фактических параметров и заключают весь их список в угловые скобки, в результате чего синтаксически получается один параметр. В теле же макроса от этого списка "отщепляют” по одному настоящему параметру и что-то с ним делают.
Далее. Макрос должен поставлять в текст окончательной программы (в макрорасширение) несколько однотипных команд PUSH г. Ясно, что здесь следует воспользоваться блоком повторения.
С учетом всего сказанного получаем такое определение нашего макроса:
5AVE MACRO REGS ;; запись в стек регистров из списка REGS
IRP R
PUSH R
ENDM
ENDM
Рассмотрим, как макрогенератор обрабатывает следующее обращение к нашему макросу:
save <AX,SI,BP>
Прежде всего, как обычно, выписывается тело макроса с заменой формального параметра на фактический:
IRP R,<AX,SI,BP>
PUSH R ENDM
Напомним, что уголки, в которые был заключен фактический параметр, считаются не относящимися к параметру и при макроподстановке удаляются. Однако в директиве IRP были свои уголки, именно они-то и сохранились в тексте, так что эта директива сохранила правильный синтаксис.