Студопедия — Макрокоманды
Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

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






С помощью макрокоманд в текст программы можно вставлять последовательности строк (которые логически могут быть данными или командами) и даже более того — привязывать их к контексту места вставки.

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

Листинг 1. Пример программы на ассемблере <1>;---------Prg_3_1.asm---------------------------------- <2>;Программа преобразования двузначного шестнадцатеричного числа <3>;в символьном виде в двоичное представление. <4>;Вход: исходное шестнадцатеричное число из двух цифр, <5>;вводится с клавиатуры. <6>;Выход: результат преобразования должен <7>;быть в регистре al. <8>;------------------------------------------------------ <9> data segment para public 'data';сегмент данных <10> message db 'Введите две шестнадцатеричные цифры,$' <11> data ends <12> stk segment stack <13> db 256 dup ('?');сегмент стека <14> stk ends <15> code segment para public 'code';начало сегмента кода <16> main proc;начало процедуры main <17> assume cs:code,ds:data,ss:stk <18> mov ax,data;адрес сегмента данных в регистр ax <19> mov ds,ax;ax в ds <20> mov ah,9 <21> mov dx,offset message <22> int 21h <23> xor ax,ax;очистить регистр ax <24> mov ah,1h;1h в регистр ah <25> int 21h;генерация прерывания с номером 21h <26> mov dl,al;содержимое регистра al в регистр dl <27> sub dl,30h;вычитание: (dl)=(dl)-30h <28> cmp dl,9h;сравнить (dl) с 9h <29> jle M1;перейти на метку M1 если dl<9h или dl=9h <30> sub dl,7h;вычитание: (dl)=(dl)-7h <31> M1:;определение метки M1 <32> mov cl,4h;пересылка 4h в регистр cl <33> shl dl,cl;сдвиг содержимого dl на 4 разряда влево <34> int 21h;вызов прерывания с номером 21h <35> sub al,30h;вычитание: (dl)=(dl)-30h <36> cmp al,9h;сравнить (al) с 9h 28 <37> jle M2;перейти на метку M2, если al<9h или al=9h <38> sub al,7h;вычитание: (al)=(al)-7h <39> M2:;определение метки M2 <40> add dl,al;сложение: (dl)=(dl)+(al) <41> mov ax,4c00h;пересылка 4c00h в регистр ax <42> int 21h;вызов прерывания с номером 21h <43> main endp;конец процедуры main <44> code ends;конец сегмента кода <45> end main;конец программы с точкой входа main  

Структурно в ней явно прослеживаются повторяющиеся участки кода. Их можно оформить в виде макрокоманд и использовать эти повторяющиеся фрагменты в различных программах.
Дальнейшее наше обсуждение будет посвящено тому, как это сделать.

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

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

имя_макрокоманды macro список_формальных_аргументов   тело макроопределения   endm  

Где должны располагаться макроопределения?
Есть три варианта:

В начале исходного текста программы до сегмента кода и данных с тем, чтобы не ухудшать читабельность программы.
Этот вариант следует применять в случаях, если определяемые вами макрокоманды актуальны только в пределах одной этой программы.

В отдельном файле.
Этот вариант подходит при работе над несколькими программами одной проблемной области. Чтобы сделать доступными эти макроопределения в конкретной программе, необходимо в начале исходного текста этой программы записать директиву include имя_файла, к примеру:

masm model small include show.inc ;в это место будет вставлен текст файла show.inc ...

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


Недостаток двух последних способов в том, что в исходный текст программы включаются абсолютно все макроопределения.
Для исправления ситуации можно использовать директиву purge, в качестве операндов которой через запятую перечисляются имена макрокоманд, которые не должны включаться в текст программы.
К примеру,

... include iomac.inc purge _outstr,_exit ...

В данном случае в исходный текст программы перед началом компиляции TASM вместо строки include iomac.inc вставит строки из файла iomac.inc. Но вставленный текст будет отличаться от оригинала тем, что в нем будут отсутствовать макроопределения _outstr и _exit.

А теперь вернемся к программе из листинга 1. Проанализируем ее текст, выявим повторяющиеся участки и составим для них макроопределения (листинг 2).

Листинг 2. Пример 1 создания и использования макрокоманд <1>;prg_3_1.asm с макроопределениями <2>init_ds macro   <3>;Макрос настройки ds на сегмент данных <4> mov ax,data <5> mov ds,ax <6> endm   <7>out_str macro str <8>;Макрос вывода строки на экран. <9>;На входе — выводимая строка. <10>;На выходе - сообщение на экране. <11> push ax <12> mov ah,09h <13> mov dx,offset str <14> int 21h <15> pop ax <16> endm <17> <18>clear_r macro rg <19>;очистка регистра rg <20> xor rg,rg <21> endm <22> <23>get_char macro <24>;ввод символа <25>;введенный символ в al <26> mov ah,1h <27> int 21h <28> endm <29> <30>conv_16_2 macro <31>;макрос преобразования символа шестнадцатеричной цифры <32>;в ее двоичный эквивалент в al <33> sub dl,30h <34> cmp dl,9h <35> jle $+5 <36> sub dl,7h <37> endm <38> <39>exit macro <40>;макрос конца программы <41> mov ax,4c00h <42> int 21h <43> endm <44> <45> data segment para public 'data' <46> message db 'Введите две шестнадцатеричные цифры (буквы A,B,C,D,E,F — прописные): $' <47> data ends <48> <49> stk segment stack <50> db 256 dup('?') <51> stk ends <52> <53> code segment para public 'code' <54> assume cs:code,ds:data,ss:stk <55> main proc <56> init_ds <57> out_str message   <58> clear_r ax <59> get_char <60> mov dl,al <61> conv_16_2 <62> mov cl,4h <63> shl dl,cl <64> get_char <65> conv_16_2 <66> add dl,al <67> xchg dl,al;результат в al <68> exit <69> main endp <70> code ends <71> end main  

В листинге 2 в строках 3–7, 9–18, 20–23, 25–30, 32–38, 40–44 описаны макроопределения. Их назначение приведено сразу после заголовка в теле каждого макроопределения.

Все эти макроопределения можно использовать и при написании других программ. Посмотрите на модернизированный исходный текст программы из листинга 3.1 в листинге 2 (строки 56–70). Если не обращать внимания на некоторые неясные моменты, то сам сегмент кода стал внешне более читабельным и даже можно сказать, что в нем появился какой то смысл.

Функционально макроопределения похожи на процедуры.
Сходство их в том, что и те, и другие достаточно один раз где-то описать, а затем вызывать их специальным образом. На этом их сходство заканчивается, и начинаются различия, которые в зависимости от целевой установки можно рассматривать и как достоинства и как недостатки:

· в отличие от процедуры, текст которой неизменен, макроопределение в процессе макрогенерации может меняться в соответствии с набором фактических параметров.
При этом коррекции могут подвергаться как операнды команд, так и сами команды. Процедуры в этом отношении объекты менее гибки;

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

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

имя_макрокоманды список_фактических_аргументов

Результатом применения данной синтаксической конструкции в исходном тексте программы будет ее замещение строками из конструкции тело макроопределения. Но это не простая замена.
Обычно макрокоманда содержит некоторый список аргументовсписок_фактических_аргументов, которыми корректируется макроопределение.
Места в теле макроопределения, которые будут замещаться фактическими аргументами из макрокоманды, обозначаются с помощью так называемых формальных аргументов.
Таким образом, в результате применения макрокоманды в программе формальные аргументы в макроопределении замещаются соответствующими фактическими аргументами; в этом и заключается учет контекста.
Процесс такого замещения называется макрогенерацией, а результатом этого процесса является макрорасширение.

К примеру, рассмотрим самое короткое макроопределение в листинге 2 — clear_rg.
Как отмечено выше, результаты работы макроассемблера можно узнать, просмотрев файл листинга после трансляции. Покажем несколько его фрагментов, которые демонстрируют, как был описан текст макроопределения clear_rg (строки 24-27), как был осуществлен вызов макрокоманды clear_rg с фактическим параметром ax (строка 58) и как выглядит результат работы макрогенератора, сформировавшего команду ассемблера xor ax,ax (строка 75);

24 clear_r macro rg 25;очистка регистра rg 26 xor rg,rg 27 endm ... 74 clear_r ax 75000E 33 C0 xor ax,ax

Таким образом в итоге мы получили то, что и требовалось — команду очистки заданного регистра, в данном случае ax.
В другом месте программы вы можете выдать ту же макрокоманду, но уже с другим именем регистра.

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

· строка может состоять из:

· последовательности символов без пробелов, точек, запятых, точек с запятой;

· последовательности любых символов, заключенных в угловые скобки: <...>. В этой последовательности можно указывать как пробелы, так и точки, запятые, точки с запятыми.
Не забывайте о том, что угловые скобки < > — это тоже оператор ассемблера. Мы упоминали о них при обсуждении директивы equ;

· для того чтобы указать, что некоторый символ внутри строки, представляющей фактический параметр, является собственно символом, а не чем-то иным, например некоторым разделителем или ограничивающей скобкой, применяется специальный оператор “! ”.
Этот оператор ставится непосредственно перед описанным выше символом, и его действие эквивалентно заключению данного символа в угловые скобки (см. предыдущий пункт);

· если требуется вычисление в строке некоторого константного выражения, то в начале этого выражения нужно поставить знак “ % ”:
% константное_выражение — значение константное_выражение вычисляется и подставляется в текстовом виде в соответствии с текущей системой счисления.

Теперь обсудим вопрос — как транслятор распознает формальные аргументы в теле макроопределения для их последующей замены на фактические аргументы?

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

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

имя_формального_аргумента[:тип]

где тип может принимать значения:

· REQ, которое говорит о том, что требуется обязательное явное задание фактического аргумента при вызове макрокоманды;

· =<любая_строка>; — если аргумент при вызове макрокоманды не задан, то в соответствующие места в макрорасширении будет вставлено значение по умолчанию, соответствующее значению любая_строка.
Будьте внимательны: символы, входящие в любая_строка, должны быть заключены в угловые скобки.

Но не всегда ассемблер может распознать в теле макроопределения формальный аргумент. Это, например, может произойти в случае, когда он является частью некоторого идентификатора. В этом случае последовательность символов формального аргумента отделяют от остального контекста с помощью специального символа &;.
Этот прием часто используется для задания модифицируемых идентификаторов и кодов операций.
К примеру, определим макрос, который предназначен для генерации в программе некоторой таблицы, причем параметры этой таблицы можно задавать с помощью аргументов макрокоманды:

... def_table macro type=b,len=REQ tabl_&type d&type len dup (0) endm ... .data def_tabl b,10 def_tabl w,5

После того как вы подвергнете трансляции текст программы, содержащий эти строки, вы получите следующие макрорасширения:

tabl_b db 10 dup (0) tabl_w dw 10 dup (0)

Символ &; можно применять и для распознавания формального аргумента в строке, заключенной в кавычки ' '. Например:

num_char macro message ;... ;подсчитать количество (num) символов в строке jmp m1 elem db 'Строка &message содержит ' ;число символов в строке message в коде ASCII num db 2 dup (0) db ' символов',10,13,'$';конец строки для вывода функцией 09h m1: ;... ;вывести elem на экран endm

В связи с рассмотрением последнего фрагмента разберем ситуацию, когда тело макроопределения содержит метку или имя в директиве резервирования и инициализации данных. Если в программе некоторая макрокоманда вызывается несколько раз, то в процессе макрогенерации возникнет ситуация, когда в программе один идентификатор будет определен несколько раз, что, естественно, будет распознано транслятором как ошибка. Для выхода из подобной ситуации применяют директиву local, которая имеет следующий синтаксис:

local список_идентификаторов

Эту директиву необходимо размещать непосредственно за заголовком макроопределения.
Результатом работы этой директивы будет генерация в каждом экземпляре макрорасширения уникальных имен для всех идентификаторов, перечисленных в список_идентификаторов. Эти уникальные имена имеют вид ??xxxx, где хххх — шестнадцатеричное число.
Для первого идентификатора в первом экземпляре макрорасширения хххх= 0000, для второго — хххх= 0001 и т. д. Контроль за правильностью размещения и использования этих уникальных имен берет на себя ассемблер.

Для того чтобы вам окончательно все стало понятно, введем и подвергнем трансляции листинг 3. В нем, кроме некоторых ранее рассмотренных макрокоманд, содержится макрокоманда num_char. Ее назначение — подсчитывать количество символов в строке, адрес которой передается этой макрокоманде в качестве фактического параметра. Строка должна удовлетворять требованию, предъявляемому к строке, предназначенной для вывода на экран функцией 09h прерывания 21h, то есть заканчиваться символом $.
Другой момент, который нашел отражение в этой программе, — использование символа $ для распознавания формального аргумента в строке, заключенной в кавычки ' ' (см. последний фрагмент).

Листинг 3. Пример 2 создания и использования макрокоманд

;prg_13_2.asm init_ds macro ;макрос настройки ds на сегмент данных mov ax,data mov ds,ax xor ax,ax endm out_str macro str ;макрос вывода строки на экран. ;На входе — выводимая строка. ;На выходе — сообщение на экране. push ax mov ah,09h mov dx,offset str int 21h pop ax endm exit macro ;макрос конца программы mov ax,4c00h int 21h endm num_char macro message local m1,elem,num,err_mes,find,num_exit ;макрос подсчета количества символов в строке. ;Длина строки — не более 99 символов. ;Вход: message — адрес строки символов, ограниченной '$' ;Выход: в al — количество символов в строке message и вывод сообщения jmp m1 elem db 'Строка &message содержит ' num db 2 dup (0);число символов в строке message в коде ASCII db ' символов',10,13,'$';конец строки для вывода функцией 09h err_mes db 'Строка &message не содержит символа конца строки',10,13,'$' m1: ;сохраняем используемые в макросе регистры push es push cx push ax push di push ds pop es;настройка es на ds mov al,'$';символ для поиска — `$` cld;сброс флага df lea di,message;загрузка в es:di смещения строки message push di;запомним di — адрес начала строки mov cx,99;для префикса repne — максимальная длина строки ;поиск в строке (пока нужный символ и символ в строке не равны) ;выход — при первом совпавшем repne scasb je find;если символ найден — переход на обработку ;вывод сообщения о том, что символ не найден push ds ;подставляем cs вместо ds для функции 09h (int21h) push cs pop ds out_str err_mes pop ds jmp num_exit;выход из макроса find:;совпали ;считаем количество символов в строке: pop ax;восстановим адрес начала строки sub di,ax;(di)=(di)-(ax) xchg di,ax;(di) <-> (ax) sub al,3;корректировка на служебные символы — 10, 13, '$' aam;в al две упакованные BCD-цифры результата подсчета or ax,3030h;преобразование результата в код ASCII mov cs:num,ah mov cs:num+1,al ;вывести elem на экран push ds ;подставляем cs вместо ds для функции 09h (int21h) push cs pop ds out_str elem pop ds num_exit: push di push ax push cx push es endm   data segment para public 'data' msg_1 db 'Строка_1 для испытания',10,13,'$' msg_2 db 'Строка_2 для второго испытания',10,13,'$' data ends   stk segment stack db 256 dup('?') stk ends   code segment para public 'code' assume cs:code,ds:data,ss:stk main proc init_ds out_str msg_1 num_char msg_1 out_str msg_2 num_char msg_2 exit main endp code ends end main

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

mes macro messsage ...;этот комментарий будет включен в текст листинга ...;;этот комментарий не будет включен в текст листинга endm

 







Дата добавления: 2015-09-18; просмотров: 585. Нарушение авторских прав; Мы поможем в написании вашей работы!



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

Функция спроса населения на данный товар Функция спроса населения на данный товар: Qd=7-Р. Функция предложения: Qs= -5+2Р,где...

Аальтернативная стоимость. Кривая производственных возможностей В экономике Буридании есть 100 ед. труда с производительностью 4 м ткани или 2 кг мяса...

Вычисление основной дактилоскопической формулы Вычислением основной дактоформулы обычно занимается следователь. Для этого все десять пальцев разбиваются на пять пар...

Механизм действия гормонов а) Цитозольный механизм действия гормонов. По цитозольному механизму действуют гормоны 1 группы...

Алгоритм выполнения манипуляции Приемы наружного акушерского исследования. Приемы Леопольда – Левицкого. Цель...

ИГРЫ НА ТАКТИЛЬНОЕ ВЗАИМОДЕЙСТВИЕ Методические рекомендации по проведению игр на тактильное взаимодействие...

ПУНКЦИЯ И КАТЕТЕРИЗАЦИЯ ПОДКЛЮЧИЧНОЙ ВЕНЫ   Пункцию и катетеризацию подключичной вены обычно производит хирург или анестезиолог, иногда — специально обученный терапевт...

Ситуация 26. ПРОВЕРЕНО МИНЗДРАВОМ   Станислав Свердлов закончил российско-американский факультет менеджмента Томского государственного университета...

Различия в философии античности, средневековья и Возрождения ♦Венцом античной философии было: Единое Благо, Мировой Ум, Мировая Душа, Космос...

Studopedia.info - Студопедия - 2014-2024 год . (0.009 сек.) русская версия | украинская версия