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

3. 6. Определение макроса через макрос

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

Пусть макрос АRR Х,N предназначен для описания массива Х из N байтов:

ARR MACRO X, N

Х DB N DUP(?)

ENDM

Тогда, используя его, можно определить макрос АRR2, предназначенный для описания сразу двух массивов одного и того же размера;

АRR2 МАСRО Х1,Х2,К

АRR Х1,<К>

АRR Х2,<К>

ENDМ

При таком макроопределении макроподстановка для макроса АRR2 проходит в два этапа, например:

АRR2 А,В,20  АRR A,< 20>  A DB 20 DUP(?)

ARR B,<20> В DВ 20 DUР(?)

Почему в теле макроса АRR2 при обращении в макросу АRR второй фактический параметр записывается в уголках? Дело в том, что если по смыслу первым и вторым параметрами макроса АRR2 могут быть только имена, то как третий параметр может быть указана достаточно сложная конструкция, например:

АRR2 А,В,<25 МОD 10>. Так вот, если бы вместо записи <К> использовалась просто запись К, тогда на первом этапе макроподстановки получилась бы макрокоманда АRR А,25 МОD 10 с четырьмя операндами, а не с двумя (напомним, что при макроподстановке уголки фактического параметра отбрасываются и что в макрокомандах параметры могут отделяться как запятыми, так и пробелами). При записи же <К> уголки заставляют рассматривать эту конструкцию как один параметр: АRR А, <25 МОD 10>.

Отметим, что в ЯА допускается вложенность макроопределений, например:

АRR2 МАСRО Х1,Х2,К

АRR МАСRО Х,N

Х DW N DUP (?)

ENDM

ARR X1,<K>

ARR X2,<K>

ENDM

Однако при этом надо учитывать следующее. Макрос АRR хотя и описан внутри макроса АRR2, не локализуется в АRR2, и к нему можно обращаться вне макроса АRR2. Но ассемблер работает так, что описание внутреннего макроса он "замечает" только при первом обращении к внешнему макросу. Поэтому обращаться к макросу АRR до обращения к макросу АRR2 нельзя:

АRR А,50 ;ошибка (имя ARR еще не описано)

АRR2 В,С,100

АRR D,60 ;можно (имя ARR уже описано)

3.7. Директива local

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

М MACRO

. . .

L: . . .

. . .

ENDM

и пусть в программе имеется два обращения к этому макросу. Тогда после макроподстановок мы получим следующую картину:

. . .

M  L: . . .

. . . . . .

M  L: . . .

. . .

Как видно, в окончательном тексте программы появились две команды, помеченные одной и той же меткой L, а это ошибка. Почему так произошло? Дело в том, что имя L не является формальным параметром макроса и потому при макроподстановке ни на что не заменяется, а переносится в макрорасширение без всяких изменений. Вот и получается, что в окончательном тексте программы будет столько меток L, сколько было обращений к данному макросу. Как избежать этой ошибки? Возможный вариант - включить метку L в число параметров макроса и при обращении к макросу указывать различные фактические метки. Однако это плохое решение, поскольку метки, которыми метятся команды тела макроса, - это чисто внутреннее дело макроса, и для того, кто будет пользоваться этим макросом, нет никакого дела до этих меток, придумывать имена для таких внутренних меток - это лишняя работа. Учитывая это, в ЯА предложено иное, более удобное решение данной проблемы. Оно заключается в том, что после заголовка макроса (директивы МАСRО) надо указать специальную директиву макроязыка:

LOCAL v1, . . . , vk (k>=1),

где vi - имена, используемые в макроопределении (обычно это метки). Тогда при макроподстановке макрогенератор будет заменять эти имена на специальные имена вида ??хххх, где хххх - четырехзначное шестнадцатеричное число, т. е. на имена ??0000, ??0001 и так далее до ??РРРР. Правила такой замены следующие. Макрогенератор запоминает номер, который он использовал в последний раз; пусть это был номер n. Когда макрогенератор встречает обращение к макросу, в котором имеется директива LOCAL, то он ставит в соответствие именам, перечисленным в этой директиве, специмена с очередными номерами: специмя ??(n+1) для v1, специмя ??(n+2) для v2 и т. д., а затем при макроподстановке заменяет каждое вхождение vi на одно и то же специмя ??(n+1). Когда макрогенератор встретит новое обращение к этому же или другому макросу, где есть директива LOCAL, то он будет уже использовать специмена с последующими номерами: n+k+1 и т. д. Поэтому в разных макрорасширениях появятся разные специмена, совпадений не будет. Рассмотрим конкретный пример. Опишем макрос, вычисляющий остаток от деления одного натурального числа на другое с помощью вычитания:

MD MACRO R1,R2 ;r1:=r1 mod r2 (r1,r2-регистры без знака)

LOCAL M, M1

M: CMP R1,R2 ;;while r1>=r2 do r1:=r1-r2

JMP M1

SUB R1,R2

JMP M

M1: ЕNDМ

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

R1→AX,R2→BX ??0017: СМР АХ,ВХ

MD AX,BX ——————————> JB ??0018

M→??0017, M1→??0018 SUB AX,BX

JMP ??0017

??0018:

R1→CX,R2→DX ??0019: СМР СХ,DХ

MD CX,DX ——————————> JВ ??001А

M→??0019, M1→??0010 SUB СХ,DХ

JMP ??0019

??001А:

Таким образом, в разных макрорасширениях появляются разные метки, и тем самым проблема с одинаковыми метками снимается. Отметим, что директиву LOCAL можно указывать только после директивы МАСRО (но зато любое число раз) и нигде более и что директива LOCAL не переносится в макрорасширение. Кроме того, следует учитывать, что специмена ??0017 и т. п. - это обычные имена, и, вообще говоря, мы можем их использовать сами, однако в силу их особой роли не рекомендуется применять эти имена в ином качестве.