Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
курсач гофаров 5 вариант.doc
Скачиваний:
6
Добавлен:
03.05.2019
Размер:
608.77 Кб
Скачать

3.1. Макрокоманды

В тех местах программы, где мы хотим, чтобы макрогенератор подставил макрос, необходимо выписать обращения к макросу в виде макрокоманды, которая записывается следующим образом:

<имя макроса> <фактические параметры через запятую>

Конкретные примеры:

SUM A,ES:B или SUM A ES: B

VAR Z,W, ? или VAR Z W, ?

Как видно, макрокоманды очень похожи на обычные команды и директивы. Но есть и отличия. Во-первых, вместо названия команды или директивы, являющегося служебным словом, в макрокоманде указывается имя макроса, которое придумал сам автор программы. Во-вторых, в макрокоманде параметры могут отделяться друг от друга как запятыми, так и пробелами. В качестве фактического параметра может быть указан любой текст (в том числе и пустой), но он должен быть сбалансирован по кавычкам и угловым скобкам и в нем не должно быть запятых, пробелов и точек с запятой вне этих кавычек и скобок. Поскольку запятыми и пробелами отделяется один параметр от другого, а с точки с запятой начинается комментарий, то их использование внутри фактического параметра привело бы к путанице. При записи параметров макрокоманд можно использовать те же макро­операторы <>, ! и %, что и при записи фактических параметров блоков повторения. Например, если в фактическом параметре надо указать запятую, пробел или точку с запятой, то параметр следует заключить в уголки:

SUM <WORD РТR [SI]>, А VAR С W <1 , 2>

При этом, напомним, уголки не считаются относящимися в параметру, а лишь указывают его границы. Число фактических параметров, указываемых в макрокоманде, вообще говоря, должно равняться числу формальных параметров макроса, причем 1-й фактичес­кий параметр соответствует 1-му формальному параметру. Однако, если факти­ческих параметров указано больше, чем надо, то лишние фактические параметры игнорируются, а если меньше, то считается, что в качестве недостающих фактических параметров заданы пустые тексты.

3. 3. Макроподстановки и макрорасширения

Теперь рассмотрим, что происходит с макрокомандами. Когда макрогенератор, просматривая исходный текст программы, встречает макрокоманду, то он выполняет макроподстановку: находит описание макроса с указанным именем, берет его тело, заменяет в этом теле все формальные параметры на со­ответствующие фактические параметры и полученный таким образом текст (он называется макрорасширением) подставляет в программу вместо макрокоманды.

Примеры (над стрелкой указано, какие формальные параметры на какие фактические параметры заменяются):

Х→А, У→ЕS:В

SUM A, ES:B ────────────> MOV AX,ES: B

ADD A, AX

NM→ , TP→W, VL→1,2

VAR ,W,<1,2> ─────────────────> DW 1,2

В общем случае макрокоманда заменяется на несколько команд, т.е. она как бы представляет собой целую группу команд. Этим и объясняется название "макрокоманда" - "большая команда".

11-3.4. Примеры использования макросов

Пример 1 (описание крупных операций в виде макросов)

Одним из существенных недостатков машинного языка, который сохраняется и в ЯА, является то, что при программировании на этих языках приходится применять мелкие операции. Например, ЭВМ умеет складывать два числа, но вот три числа она сама по себе уже сложить не может, поэтому мы вынуждены указывать ей, как это делается. И такое сведение к мелким операциям приходится делать для любого алгоритма, сколь бы сложным он ни был. В этом и заключается основная сложность программирования на ЯА. В определенной мере этот недостаток можно устранить с помощью макросов. Для этого надо в виде макросов описать более крупные операции, а затем составлять программу с использованием этих макросов.

Пусть, к примеру, в нашей программе многократно встречается условный переход "по меньше": if х<у then goto L. Эта операция реализуется тремя командами. Чтобы их каждый раз не выписывать заново, имеет смысл описать их как макрос, а затем пользоваться им. Давайте так и сделаем. Дадим этому макросу имя if_less и будем считать, что числа у нас знаковые и размером в слово:

IF_LESS МAСRО Х,Y,L

MOV АХ, Х

СМР АХ,Y

JL L

ENDM

Имея такой макрос, можно, к примеру, следующим образом описать вычисление минимума трех чисел DХ=min(А,В,С):

MOV DX,A MOV DX,A

IF_LESS A, B, M1 ──── X→DX, Y→C, L→M2 MOV AX,A

MOV DX,B ‌‌ CMP AX,B

M 1: IF_LESS DX, C, M2──── J L M1

MOV DX,C MOV DX,B

M2: . . . X→DX, Y→C, L→M2 M1:

MOV AX, DX

CMP AX,C

J L M2

MOV DX,C

M2: . . .

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

Пример 2 (макросы и обращения к процедурам)

Предположим, что имеется процедура NOD, вычисляющая наибольший общий делитель двух чисел: Z=NOD(Х,Y), и что параметр Х передается ее через регистр АХ, параметр Y - через ВХ, а результат Z возвращается через АХ. И пусть надо вычислить СX=NОD(А,В)+NОD(С,D). Тогда фрагмент программы, реализующий это вычисление, выглядит так:

МOV АХ,А

МОV ВХ,В

CALL. NOD

МОV СХ,АХ

МОV АХ,С

МОV ВХ,D

САLL NOD

АDD СХ,АХ

Легко заметить, что при каждом обращении к процедуре приходится выписывать фактически одну и ту же группу команд. Так вот, чтобы их не выписывать каждый раз заново, можно эту группу команд описать как макрос, а затем его и использовать. Описание этого макроса выглядит так:

CALL_NOD MACRO X,Y

MOV АХ,Х

MOV BX,Y

CALL NOD

ENDM

а нужный нам фрагмент программы:

САLL_NOD А,В

MOV СХ,АХ

САLL_NOD С,D

АDD СХ,АХ

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

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

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

SAVE МАСRО RЕGS ;;запись в стек регистров из списка REGS

IPR R,<REGS>

PUSH R

ENDM

ENDM

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

SAVE <АХ,SI,ВР>

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

IRР R,<АХ, SI, ВР>

РUSH R

ЕNDM

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

PUSH AX

РUSН SI

РUSH ВР

который и является окончательным макрорасширением нашей макрокоманды.