Автор работы: Пользователь скрыл имя, 04 Апреля 2013 в 20:43, лекция
Макропроцессор — модуль системного ПО, позволяющий расширить возможности языка Ассемблера за счет предварительной обработки исходного текста программы.
Определение, которое показанное выше, не представляется удачным, так как оно говорит только о сокращении объема записи, а это лишь одна из возможностей обеспечиваемых Макропроцессором. Хотя Макропроцессоры являются обязательным элементом всех современных языков Ассемблеров, аналогичные модули (Препроцессоры) могут быть и для других языков, в том числе и для языков высокого уровня. Для одних языков (Pascal, PL/1) применение средств препроцессора является опционным, для других (C, C++) — обязательным.
Как правило, операции присваивания могут применяться к параметрам макроопределения точно так же, как и к переменным макроопределения.
Глобальные переменные макроопределения
Значения локальных переменных
макроопределения сохраняются только
при обработке данного
Объявление глобальной переменной макроопределения может иметь, например, вид:
имя_переменной GLBL начальное_значение (последнее необязательно)
Присваивание значений глобальным переменным макроопределения выполняется так же, как и локальным.
Уникальные метки
В некоторых случаях операторы машинных команд, имеющихся в макроопределении, должны быть помечены, например, для того, чтобы передавать на них управление. Если применить для этих целей обычную метку, то может возникнуть ошибочная ситуация. Если метка в макроопределении имеет обычное имя, и в модуле данная макрокоманда вызывается два раза, то будет сгенерировано два макрорасширения, и в обоих будет метка с этим именем. Чтобы избежать ситуации неуникальности меток, в макроязыке создается возможность определять метки, для которых формируются уникальные имена. Обычно имя такой метки имеет тот же отличительный признак, который имеют параметры и переменные макроопределения. Каждую такую метку Макропроцессор заменяет меткой с уникальными именем.
Уникальное имя метки может формироваться формате, подобном следующему:
&имя.nnnnnn
где — nnnnnn — число, увеличивающееся на 1 для каждой следующей уникальной метки.
Другой возможный способ формирования, например:
имя&SYSNDX
где SYSNDX — предустановленное имя, имеющее числовое значение, начинающееся с 00001 и увеличивающееся на 1 для каждой следующей уникальной метки.
Следующие операторы Макроязыка влияют на последовательность обработки операторов макроопределения. В тех или иных Макропроцессорах имеется тот или иной набор таких операторов.
Оператор безусловного перехода и метки макроопределения
Возможный формат оператора:
MGO макрометка
Концептуально важным понятием является макрометка. Макрометка может стоять перед оператором Макроязыка или перед оператором языка Ассемблера. Макрометки не имеют ничего общего с метками в программе. Передача управления на макрометку означает то, что при обработке макроопределения следующим будет обрабатываться оператор, помеченный макрометкой. Макрометки должны иметь какой-то признак, по которому их имена отличались бы от имен программы и переменных макроопределения. Например, если имена переменных макроопределения начинаются с символа &, то имя макрометки может начинаться с &&.
Оператор условного перехода
Возможный формат оператора:
MIF условное_выражение макрометка
Если условное_выражение имеет значение «истина», обработка переходит на оператор, помеченный макрометкой, иначе обрабатывается следующий оператор макроопределения. Условные выражения формируются по обычным правилам языков программирования. В них могут употребляться параметры и переменные (локальные и глобальные) макроопределения, константы, строковые, арифметические и логические операции и, конечно же, операции сравнения.
Кроме того, в составе Макроязыка обычно имеются специальные функции, позволяющие распознавать тип своих операндов, например: является ли операнд строковым представлением числа, является ли операнд именем, является ли операнд именем регистра.
Условные блоки
Возможный формат оператора:
IF условное_выражение
операторы_макроопределения_
ENDIF
ELSE
операторы_макроопределения_
ENDIF
Если условное_выражение имеет значение «истина», обрабатываются операторы макроопределения от оператора IF до оператора ENDIF, иначе обрабатываются операторы макроопределения от оператора ESLE до оператора ENDIF. Как и в языках программирования блок ELSE — ENDIF не является обязательным.
Условные выражения описаны выше. Обычно предусматриваются специальные формы:
IFDEF имя
IFNDEF имя
проверяющие просто определено или не определено данное имя.
Операторы условных блоков довольно часто являются не операторами Макроязыка, а директивами самого языка Ассемблера.
Операторы повторений
Операторы повторений Макроязыка (или директивы повторений языка Ассемблера) заставляют повторить блок операторов исходного текста, возможно, с модификациями в каждом повторении. Операторы повторений играют роль операторов цикла в языках программирования, они не являются обязательными для макроязыка, так как цикл можно обеспечить и условным переходом.
Как и в языках программирования, в Макроязыке может быть несколько форм операторов повторения, приведем некоторые (не все) из возможных форм:
MDO выражение
блок_операторов_
ENDMDO
выражение должно иметь числовой результат, обработка блока операторов повторяется столько раз, каков результат вычисления выражения.
MDOLIST переменная_макроопределения,
список_выражений
блок_операторов_
ENDMDO
обработка блока операторов
повторяется столько раз, сколько
элементов имеется в списке_
MDOWHILE условное_выражение
блок_операторов_
ENDMDO
обработка блока операторов повторяется до тех пор, пока значение условного_выражения — «истина».
Выдача сообщения
При возникновении ошибок или ситуаций, требующих предупреждения программисту в листинг должно выводиться сообщение. Если в результате ошибки программиста, написавшего макроопределение или макровызов будет сгенерирован неправильный код программы на языке Ассемблера, то эта ошибка будет выявлена только Ассемблером на этапе трансляции программы. Однако выгоднее выявлять ошибки не как можно более ранних этапах подготовки программы, в Макроязыке ошибочные ситуации (ошибки в параметрах и т.п.) могут быть выявлены при помощи условных операторов или блоков, а для выдачи сообщения об ошибке должен существовать специальный оператор Макроязыка. Формат такого оператора примерно следующий:
MOTE код_серьезности,код_ошибки,
код_серьезности — числовой код, определяющий возможность продолжения работы при наличии ситуации, вызвавшей сообщения.
Должны индицироваться, как минимум, следующие ситуации:
u работа Макропроцессора может быть продолжена, по окончании ее может выполняться ассемблирование;
u работа Макропроцессора может быть продолжена, но ассемблирование выполняться не может;
u работа Макропроцессора не может продолжаться.
код_ошибки — числовой код, служащий, например, для поиска развернутого описания сообщений и действий при его возникновении в документе «Сообщения программы»
сообщение_об_ошибке — текст, печатаемый в листинге
Завершение обработки
Обработка макроопределения завершается при достижении оператора MEND. Однако, поскольку алгоритм обработки макроопределения может разветвляться, должна быть предусмотрена возможность выхода из обработки и до достижения конца макроопределения. Эта возможность обеспечивается оператором MEXIT. Операндом этого оператора может быть код_серьезности.
Комментарии макроопределения
Если в тексте макроопределения имеются комментарии, то они переходят в макрорасширение так же, как и операторы машинных команд и директив Ассемблера. Однако, должна быть обеспечена и возможность употребления таких комментариев, которые не переходят в макрорасширение — комментарии, которые относятся не к самой программе, а к макроопределению и порядку его обработки. Такие комментарии должны обладать некоторым отличительным признаком. Возможны специальные директивы Ассемблера, определяющие режим печати комментариев макроопределения.
Макрорасширения в листинге
Как уже неоднократно говорилось, макрорасширения для Ассемблера неотличимы от программного текста, написанного программистом «своей рукой». Но программист, анализируя листинг программы, конечно, должен видеть макрорасширения и отличать их от основного текста. Как правило, директивы Ассемблера, управляющие печатью листинга предусматривают режим, при котором макрорасширение не печатается в листинге, а печатается только макрокоманда и режим, при котором в листинге печатается и макрокоманда, и ее макрорасширение, но операторы макрорасширения помечаются каким-либо специальным символом.
Структуры данных Макропроцессора
Таблица макроопределений, строго говоря, не таблица, а просто массив строк, в который записываются тексты всех макроопределений (от оператора MACRO до оператора MEND), найденных в обрабатываемом модуле.
Таблица имен макроопределений содержит имена макроопределений и указатель на размещение текста макроопределения в таблице макроопределений, как показано на рисунке.
Все таблицы имеют переменный размер и заполняются в процессе работы. Индекс уникальных меток — число, используемое для формирования уникальной части имен меток, встречающихся в макроопределениях
Для обработки каждого макровызова создаются:
u Таблица параметров, содержащая информацию о параметрах макроопределения.
u Таблица локальных переменных, содержащая информацию о локальных переменных макроопределения.
Структура этих таблиц — такая же, как и таблицы глобальных переменных, эти две таблицы могут быть объединены в одну таблицу параметров и локальных переменных.
Алгоритм работы Макропроцессора
Очевидно, что когда Макропроцессор обрабатывает макровызов, он уже должен «знать» макроопределение данной макрокоманды. Для обеспечения этого таблицы макроопределений и имен макроопределений должны быть созданы до начала обработки макровызовов. Поэтому Макропроцессор должен состоять из двух проходов, на первом проходе строятся таблицы макроопределений и имен макроопределений, а на втором осуществляется обработка макровызовов. Если макроопределения сосредоточены в начале исходного модуля, то Макропроцессор может быть и однопроходным. Ниже мы приводим алгоритм работы 2-проходного Макропроцессора, при этом мы исходим из следующих предпосылок:
u наш Макропроцессор является независимым от Ассемблера;
u таблица параметров объединяется с таблицей локальных переменных, в дальнейшем мы называем объединенную таблицу таблицей локальных переменных;
u операторы Макроязыка включают в себя: MACRO, MEND, MEXIT, MNOTE, LOCL, GLBL, SET, MGO, MIF;
u обеспечиваются локальные и глобальные переменные макроопределений, уникальные метки.
Библиотеки макроопределений
Макровызовы к макроопределение, приведенному в исходном модуле, могут применяться только в этом же исходном модуле. Для того, чтобы можно было использовать макроопределение в разных исходных модулях, макроопределения помещаются в библиотеку макроопределений. Список библиотек макроопределений, которые используются для данного исходного модуля является параметром Макропроцессора.
Мы в нашей схеме алгоритма показали, что обращение к библиотекам макроопределений происходит на 2-м проходе Макропроцессора — если мнемоника оператора не распознана ни как оператор языка Ассемблера, ни как макрокоманда, определенная в данном исходном модуле. Возможны, однако, и другие алгоритмы использования библиотек.
Один из таких алгоритмов следующий.
Анализ мнемоники производится на 1-м проходе Ассемблера, все операторы, не распознанные как операторы языка Ассемблера, считаются макрокомандами и для них создаются строки в Таблице имен макроопределений.
Если для такой макрокоманды макроопределение еще не найдено, поле ссылки на Таблицу макроопределений остается пустым.
Если в исходном модуле встречается макроопределение, то его текст заносится в Таблицу макроопределений. Если в Таблице имен макроопределений уже есть это имя с пустой ссылкой на Таблицу макроопределений, ссылке присваивается значение. Если такого имени в Таблице имен макроопределений нет, в таблице создается новая строка.
В конце 1-го прохода просматривается Таблица имен макроопределений. Если в таблице находятся имена с пустыми ссылками на Таблицу макроопределений, соответствующее макроопределение ищется в библиотеках. Если макроопределение найдено в библиотеке, его текст переписывается в Таблицу макроопределений и присваивается значение ссылке в соответствующей строке Таблицы имен макроопределений.
Если после этого в Таблице имен макроопределений остаются имена с пустыми ссылками, это свидетельствует об ошибках в программе.
Вложенные макровызовы.
Вложенные макроопределения
Можно ли употреблять макроопределения
внутри макроопределений? Можно ли
употреблять макровызовы вызовы
внутри макроопределений? Представленные
выше алгоритмы делать этого не позволяют.
Тем не менее, можно построить
такие алгоритмы