Читать «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.)

Пример 3 (макросы и блоки повторения)

При входе в процедуру, как правило, требуется спасать в стеке содержимое регистров, для чего приходится выписывать несколько команд PUSH. И если в программе много процедур, если такая группа команд встречается многократно, то имеет смысл описать ее в виде макроса. Рассмотрим, как выглядит такой макрос.

Прежде всего отметим, что по смыслу у этого макроса может быть любое число фактических параметров (разное число названий регистров). Поскольку в ЯА можно определять макросы только с фиксированным числом формальных параметров, то в подобных ситуациях обычно поступают так: макрос описывают с одним формальным параметром, но при обращении к нему (в макрокоманде) указывают через запятую нужное число фактических параметров и заключают весь их список в угловые скобки, в результате чего синтаксически получается один параметр. В теле же макроса от этого списка "отщепляют” по одному настоящему параметру и что-то с ним делают.

Далее. Макрос должен поставлять в текст окончательной программы (в макрорасширение) несколько однотипных команд PUSH г. Ясно, что здесь следует воспользоваться блоком повторения.

С учетом всего сказанного получаем такое определение нашего макроса:

5AVE MACRO REGS ;; запись в стек регистров из списка REGS

IRP R,<REGS>

PUSH R

ENDM

ENDM

Рассмотрим, как макрогенератор обрабатывает следующее обращение к нашему макросу:

save <AX,SI,BP>

Прежде всего, как обычно, выписывается тело макроса с заменой формального параметра на фактический:

IRP R,<AX,SI,BP>

PUSH R ENDM

Напомним, что уголки, в которые был заключен фактический параметр, считаются не относящимися к параметру и при макроподстановке удаляются. Однако в директиве IRP были свои уголки, именно они-то и сохранились в тексте, так что эта директива сохранила правильный синтаксис.