Макроопределения

    Макрокоманда - это программный инструмент, который позволяет вам

    создавать собственные операции ассемблера. На самом деле макро-

    определения относятся к механизму препроцессора. Макропроцессор

    позволяет определять новые коды операций для процессора. В этом

    определении вы, в частности, сообщаете ассемблеру текст выполняемой

    операции. Когда ассемблер встречает этот вновь определенный код

    операции, он обращается к сохраненному определению макрокоманды и

    помещает в транслируемый участок программы текст из этого

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

    макрокоманд часто используемые последовательности команд. Каждый

    раз, когда эти команды должны быть вставлены в текст программы,

    программист может вместо этого воспользоваться макрокомандой.

 

      В использовании макрокоманды можно выделить два шага. На первом

    шаге макрокоманда определяется в программе. Программист присваивает

    ей имя и определение. Определение состоит из из операций ассемблера

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

    имени макрокоманды. Второй шаг - применение макрокоманды. Это

    происходит когда ассемблер встречает ее имя в качестве кода

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

    командами.

 

      Возьмем в качестве примера команды сопроцессора 8087, который

    мы обсудим в глве 7. В написании программ с использованием команд

    числового процессора 8087 возникают некоторые трудности. В

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

    8087 вы должны сформировать его команды с помощью либо оператора

    определения данных, либо кодов операций WAIT и ESC. Лучше всего это

    делать через определение макрокоманды, что позволит вам писать

    команды 8087. После этого программа может пользоваться командами

    8087, хотя они и не входят в язык ассемблера.

 

      В программировании на языке ассемблера макрокоманды исполь-

    зуются наиболее часто. Хотя видимых причин не применять макропро-

    цессор в языках высокого уровня нет, там макрокоманды встречаются

    довольно редко. Макроассемблер для IBM PC поддерживает

    макрокоманды. Как мы уже отмечали, существует две версии

    ассемблера. Малый ассемблер, ASM, не поддерживает это средство.

    Полный ассемблер, MASM, допускает все макрооперации, которые обсуж-

    даются в этой главе. Для использования MASM ваш персональный

    компьютер должен иметь как миимум 96K оперативной памяти.

 

      Простейшая макрокоманда, которую можно использовать как код

    операции 8087, - FENI. Макроассеблер 8088 не распознает ключевого

    слова FENI, которое в действительности является командой для 8087.

    Фиг. 6.1 показывает два шага макро-процесса: определение

    макрокоманды FENI и ее последующий вызов в программе. Фиг.6.1

    состоит из двух частей: часть (a) - это исходный файл для

    программы, а часть (b) содержит листинг ассемблера для нее. Два

    варианта на Фиг. 6.1 разделены, чтобы показать, какой из них

    написан программистом, а какой сгенерирован макропроцессором.

 

      Программа определяет макрокоманду с помощью ключевого слова

    MACRO. На Фиг. 6.1 макроопределение выглядит так:

 

      FENI  MACRO

      ;---- Тело макрокоманды

            ENDM

 

    Оператор MACRO является кодом псевдооперации. Эта конкретная псев-

    дооперация сообщает ассемблеру, что начинается определение макроко-

    манды. В поле имени операции указано это имя, которое программа

    приписывает определяемой макрокоманде, в нашем случае FENI. Команды

                  PAGE    ,132

                  TITLE   Фиг. 6.1 Макрокоманда

 

            FENI    MACRO

                  DB      0DBH, 0E0H

                  ENDM

 

            CODE    SEGMENT

                  ASSUME  CS:CODE

 

                  FENI

            CODE    ENDS

                  END

 

                  Фиг. 6.1 (a) Исходный файл для программы

         Microsoft (R) Macro Assembler Version 5.00                1/1/80 04:02:38

         Фиг. 6.1 Макрокоманда                               Page 1-1

 

                                       PAGE    ,132

                                       TITLE   Фиг. 6.1 Макрокоманда

 

                                 FENI    MACRO

                                       DB    0DBH, 0E0H

                                       ENDM

 

          0000                   CODE    SEGMENT

                                       ASSUME  CS:CODE

 

                                       FENI

          0000  DB E0         1        DB    0DBH, 0E0H

          0002                   CODE    ENDS

                                       END

 

                  Фиг. 6.1 (b) Листинг ассмблера программы

 

    Фиг.6.1 Макроопределение.(a) исходный файл; (b) листинг ассемблера.

 

    (или действия ассемблера), которые будут заменять имя макрокоманды,

    следуют за строкой заголовка. Наконец, ключевое слово ENDM

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

    MSCRO и ENDM называется телом макрокоманды. На Фиг. 6.1 телом

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

    8088 нет команды, которая соответствовала бы команде FENI код

    машинного языка для этой команды должен состять из операторов DB.

      Важно заметить, что во время определения макрокоманды код

    машинного языка еще не генерируется. Это можно утверждать, потому

    что колонки адреса и данных в листинге ассемблера пусты. Когда

    ассемблер впервые встречае макроопределение, он сохраняет его для

    дальнейшего использования. Затем программа на Фиг. 6.1 привлекает

    макрокоманду FENI. Программист использует имя макрокоманды FENI как

    если бы это был код оперции ассемблера типа CLD или DAA, а

    ассемблер обращается к сохраненному определению макрокоманды FENI.

    Ассемблер берет текст из тела макроопределения и помещает его в той

    же позиции транслируемой программы. Знак "+", появляющийся слева от

    оператора DB в распечатке ассемблера, указывает на то, что эта

    строка вставлена макропроцессором. Если сравнить исходный текст с

    ассемблируемым, вы увидите в исходном тексте только команду FENI, в

    то время как на листинге ассемблера за командой FENI следует тело

    макрокоманды. В данном случае оно представлено одним оператором DB.

      Этот простой пример демонстрирует большие возможности

    макропроцессора. Возникла необходимость в коде операции FENI,

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

    макрокоманд программист был бы вынужден вместо операции FENI каждый

    раз записывать ее код:

 

      DB 0DBH, 0E0H

 

    Имея же в распоряжении такой механизм, можно определить

    макрокоманду FENI и в дальнейшем в этой же программе использовать

    как код операции только ее. Для использования подобных макрокоманд

    есть две серьезные причины. Во-первых, они облегчают написание

    программы. Во-вторых, при чтении текста программы оператор FENI,

    выглядит гораздо более осмысленным, чем DB 0DBH,0E0H.

 

      Макрокоманду можно сравнить с подпрограммой. Подпрограмма - это

    участок программы, определяемый в единственном месте программы,

    Программа может передать управление подпрограмме из любой своей

    точки. Использование подпрограмм экономит время написания и объем

    памяти, занимаемый программой. Вместо того, чтобы каждый раз

    переписывать команды подпрограммы, когда необходимо ее выполнение,

    вы вставляете ее вызов. Подпрограмма выполняет свою определенную

    функцию, и управление возвращантся в точку вызова.

 

      Макрокоманда точно также определяется в ассемблируемой

    программе в единственном месте. После того, как макрокоманда

    определена, ее можно привлечь ("вызвать") в любой точке

    транслируемой программы. Использование макрокоманды экономит время

    составления программ и место, занимаемое исходным файлом. Вместо

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

    переписывать входящие в макрокоманду команды, в программу

    вставляется вызов макрокоманды. Ассемблер генерирует заданные в

    определении команды и переходит к обработке следующего кода

    операции.

 

      Разница между макрокомандой и подпрограммой заключается в

    моменте их использования. Макрокоманда является операцией текстовой

    обработки. Она определяется и "выполняется" во время

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

    макрокоманды текстом, составляющим тело макрокоманды. Подпрограмма

    же хотя и определяется при ассемблировании, но выполняется не

    раньше, чем сама программа. Мы будем говорить, что макрокоманда

    выполняется при ассемблировании, а подпрограмма - во время

    выполнения программы.

 

      Лучший способ отличить макрокоманду от подпрограммы - это

    запомнить, когда они проявляются. На самом деле, макропроцессор не

    является атрибутом языка программирования. Допустим, вы - адвокат,

    и составляете завещания для множества разных людей. Так как

    завещания часто похожи, то вы могли бы задать набор

    "макрозавещаний", которые будут содержать совпадающие части

    составляемых завещаний. Первая часть завещания, где перечислены

    участвующие в нем стороны, будет уникальной. Оставшаяся часть будет

    состоять из различных макрозавещаний, охватывающих стандартные

    куски завещаний. Результатом работы "процессора завещаний" будет

    текстовый документ. Макрозавещания раскрываются и образуют

    стандартную часть завещания. Вам остается только заполнить

    переменные фрагменты документа между макрозавещаниями.

 

      Но если макрокоманды и подпрограммы во многих отношениях так

    похожи, то зачем использовать вместо процедуры макрокоманду?

    Действительно, во многих случаях применима любая из них.

    Последовательность команд может быть определена и как макрокоманда,

    и как подпрограмма. Когда вам потребуется эта последовательность,

    вы можете вызвать соответственно макрокоманду или подпрограмму.

    Какую именно - зависит от того, как вы определили данную

    последовательность команд. Выбор последнего задается соображениями

    времени выполнения программы и объема занимаемой ею памяти. В

    большинстве случаев использование макрокоманд приводит к более

    длинным программа, т.е. для реализации одной и той же функции

    требуется больше байтов объектного кода. Однако такая программа

    выполняется быстрее так как отсутствуют временные издержки,

    связанные с вызовом подпрограммы и возвратом в программу каждый

    раз, когда требуется данная последовательность команд. Для

    минимизации размера программы слудет использовать подпрограммы.

    Чтобы иметь программу с максимальным быстродействием, вы

    пользуетесь макрокомандами.

 

      В случае макрокоманды FENI на Фиг. 6.1, выбор в пользу

    макрокоманды очевиден. Здесь соответствующий участок программы в

    качестве макрокоманды не только выполняется быстрее нежели, в

    качестве подпрограммы, но и занимает меньше памяти. Команда CALL

    для близкой процедуры требует три байта. Макрокоманды FENI - только

    два байта. В случае макрокоманд для процессора 8087 для реализации

    тех же функций через процедуры потребовалось бы больше байтов

    объектного кода. Кроме того использование макрокоманд сокращает

    время выполнения программы.