Автор работы: Пользователь скрыл имя, 04 Апреля 2013 в 20:43, лекция
Макропроцессор — модуль системного ПО, позволяющий расширить возможности языка Ассемблера за счет предварительной обработки исходного текста программы.
Определение, которое показанное выше, не представляется удачным, так как оно говорит только о сокращении объема записи, а это лишь одна из возможностей обеспечиваемых Макропроцессором. Хотя Макропроцессоры являются обязательным элементом всех современных языков Ассемблеров, аналогичные модули (Препроцессоры) могут быть и для других языков, в том числе и для языков высокого уровня. Для одних языков (Pascal, PL/1) применение средств препроцессора является опционным, для других (C, C++) — обязательным.
Макропроцессоры
Основные понятия
Макропроцессор — модуль системного ПО, позволяющий расширить возможности языка Ассемблера за счет предварительной обработки исходного текста программы.
Определение, которое показанное выше, не представляется удачным, так как оно говорит только о сокращении объема записи, а это лишь одна из возможностей обеспечиваемых Макропроцессором. Хотя Макропроцессоры являются обязательным элементом всех современных языков Ассемблеров, аналогичные модули (Препроцессоры) могут быть и для других языков, в том числе и для языков высокого уровня. Для одних языков (Pascal, PL/1) применение средств препроцессора является опционным, для других (C, C++) — обязательным.
Важно понимать, что Макропроцессор осуществляет обработку исходного текста. Он «не вникает» в синтаксис и семантику операторов и переменных языка Ассемблера, не знает (как правило) имен, употребляемых в программе, а выполняет только текстовые подстановки. В свою очередь, Ассемблер обрабатывает исходный текст, не зная, написан тот или иной оператор программистом «своей рукой» или сгенерирован Макропроцессором. По тому, насколько Препроцессор (Макропроцессор) и Транслятор (Ассемблер) «знают» о существовании друг друга, их можно разделить на три категории:
u Независимые. Препроцессор составляет отдельный программный модуль (независимую программу), выполняющую просмотр (один или несколько) исходного модуля и формирующую новый файл исходного модуля, поступающий на вход Транслятора (пример — язык C).
u Слабосвязанные. Препроцессор составляет с Транслятором одну программу, но разные секции этой программы. Если в предыдущем случае Препроцессор обрабатывает весь файл, а затем передает его Транслятору, то в этом случае единицей обработки является каждый оператор исходного текста: он обрабатывается секцией Препроцессора, а затем передается секции Транслятора. (Пример — HLASM для S/390).
u Сильносвязанные. То же распределение работы, что и в предыдущем случае, но Препроцессор использует некоторые общие с Транслятором структуры данных. Например, Макропроцессор может распознавать имена, определенные в программе директивой EQU и т.п.
(Пример — MASM, TASM).
Основные термины, связанные
с данными, обрабатываемыми
u макровызов (или макрокоманда);
u макроопределение;
u макрорасширение.
Макровызов или макрокоманда или макрос — оператор программы, который подлежит обработке Макропроцессором (Макропроцессор обрабатывает не все операторы, а только ему адресованные).
Макроопределение — описание того, как должна обрабатываться макрокоманда, макроопределение может находиться в том же исходном модуле, что и макрокоманда или в библиотеке макроопределений.
Макрорасширение — результат выполнения макровызова, представляющий собой один или несколько операторов языка Ассемблера, подставляемых в исходный модуль вместо оператора макровызова. Пример обработки макровызова показан на рисунке.
Оператор макровызова в исходной программе имеет тот же формат, что и другие операторы языка Ассемблера: В нем есть метка (необязательно), мнемоника и операнды. При обработке исходного текста если мнемоника оператора не распознается как машинная команда или директива, она считается макрокомандой и передается для обработки Макропроцессору.
Макроопределение описывает, как должна обрабатываться макрокоманда. Средства такого описания составляют некоторый Макроязык. Для Макропроцессоров 1-й и 2-й категорий средства Макроязыка могут быть достаточно развитыми. Для Макропроцессоров 3-й категории средства Макроязыка могут быть довольно бедными, но в составе языка Ассемблера может быть много директив, применяемых в макроопределениях (возможно, — только в макроопределениях). В теле макроопределения могут употребляться операторы двух типов:
u операторы Макроязыка, которые не приводят к непосредственной генерации операторов макрорасширения, а только управляют ходом обработки макроопределения;
u операторы языка Ассемблера (машинные команды и директивы), которые переходят в макрорасширение, возможно, с выполнением некоторых текстовых подстановок.
Поскольку макроопределение, обрабатывается перед трансляцией или вместе с ней, макрокоманда, определенная в исходном модуле, может употребляться только в этом исходном модуле и «не видна» из других исходных модулей. Для повторно используемых макроопределений обычно создаются библиотеки макроопределений. В некоторых системах (например, z/OS) макрокоманды обеспечивают системные вызовы и существуют богатейшие библиотеки системных макроопределений.
Самое очевидное применение макрокоманд — для сокращения записи исходной программы, когда один оператор макровызова заменяется на макрорасширение из двух и более операторов программы. В некоторых случаях макрорасширение может даже содержать и единственный оператор, но просто давать действию, выполняемому этим оператором более понятную мнемонику. Но возможности Макропроцессора гораздо шире. Так, одна и та же макрокоманда с разными параметрами может приводить к генерации совершенно различных макрорасширений — и по объему, и по содержанию.
Сравнение макросредств и подпрограмм
Использование макросредств во многом подобно использованию подпрограмм: в обоих случаях мы сокращаем запись исходного текста и создаем повторно используемые фрагменты кода. (Например, в C/C++ вызов псевдофункции неотличим от вызова функции.)
Принципиальные различия между подпрограммами и макросредствами:
u Команды, реализующие подпрограмму, содержатся в кода загрузочного модуля один раз, а команды, реализующие макровызов, включаются в программу для каждого применения макровызова (макросредства требуют больше памяти).
u Выполнение подпрограммы требует передачи управления с возвратом — команды типа CALL и RET, а команды макрорасширения включаются в общую последовательность команд программы (макровызовы выполняются быстрее).
Если в многофункциональной подпрограмме имеется разветвление в зависимости от значений параметров, то в загрузочный модуль включается код подпрограммы в полном объеме, даже если в конкретной программе реально используется только одна из ветвей алгоритма; в макровызове в каждое макрорасширение включаются только операторы, определяемые фактическими значениями параметров макровызова (экономия и времени и объема в макровызовах).
Общий итог сравнения: макросредства обеспечивают несколько большее быстродействие при несколько больших затратах памяти. Поэтому обычно макросредства применяются для оформления сравнительно небольших фрагментов повторяющегося кода.
Некоторые возможности Макроязыка
Ниже мы описываем некоторые возможности макроязыка, в той или иной форме реализованные во всех Макропроцессорах. Мы, однако, ориентируемся прежде всего на Макропроцессор, независимый от Ассемблера, потому что в этой категории функции Макропроцессора легче определить.
Заголовок макроопределения
Макроопределение должно как-то выделяться в программе, поэтому оно всегда начинается с заголовка.
Заголовок имеет формат, подобный следующему:
имя_макрокоманды MACRO список формальных параметров
имя_макрокоманды является обязательным компонентом. При макровызове это имя употребляется в поле мнемоники оператора. Имена макроопределений, имеющихся в программе, должны быть уникальны. Обычно при распознавании макровызова поиск по имени макрокоманды ведется сначала среди макроопределений имеющихся в программе, а затем (если в программе такое макроопределение не найдено) — в библиотеках макроопределений. Таким образом, имя макрокоманды, определенной в программе, может совпадать с именем макрокоманды, определенной в библиотеке, в этом случае макрокоманда, определенная в программе, заменяет собой библиотечную.
Формальные параметры играют ту же роль, что и формальные параметры процедур/функций. При обработке макровызова вместо имен формальных параметров в теле макроопределения подставляются значения фактических параметров макровызова.
В развитых Макроязыках возможны три формы задания параметров:
u позиционная;
u ключевая;
u смешанная.
При использовании позиционной формы соответствие фактических параметров формальным определяется их порядковым номером. (Позиционная форма всегда применяется для подпрограмм).
В позиционной форме количество и порядок следования фактических параметров макровызова должны соответствовать списку формальных параметров в заголовке макроопределения. При использовании ключевой формы каждый фактический параметр макровызова задается в виде:
имя_параметра=значение_
В таком же виде они описываются и в списке формальных параметров, но здесь значение_параметра может опускаться. Если значение_параметра в списке формальных параметров не опущено, то это — значение по умолчанию. В макровызове параметры могут задаваться в любом порядке, параметры, имеющие значения по умолчанию, могут опускаться.
В смешанной форме первые несколько параметров подчиняются правилам позиционной формы, а остальные — ключевые.
В некоторых Макропроцессорах имена параметров начинаются с некоторого отличительного признака (например, амперсанда — &), чтобы Макропроцессор мог отличить «свои» имена (имена, подлежащие обработке при обработке макроопределения) от имен, подлежащих обработке Ассемблером. Для Макропроцессоров, которые мы отнесли к категории сильносвязанных такой признак может и не быть необходимым, так как такой Макропроцессор обрабатывает как свои имена, так и имена Ассемблера. В любом случае возникает проблема распознавания имени в теле макроопределения. Например, если макроопределение имеет формальный параметр &P, а в макровызове указано для него фактическое значение 'X', то как должна обрабатываться подстрока '&PA' в теле макроопределения? Должна ли эта подстрока быть заменена на 'XA' или оставлена без изменений?
Логика, которой следует большинство Макропроцессоров в этом вопросе, такова. &PA является именем в соответствии с правилами формирования имен. Поэтому оно не распознается как имя &P и остается без изменений. Если мы хотим, чтобы подстановка в этой подстроке все-таки произошла, следует поставить признак, отделяющий имя параметра от остальной части строки. Обычно в качестве такого признака используется точка — '.': '&P.A' заменяется на 'XA'.
Окончание макроопределения
Если у макроопределения есть начало (оператор MACRO), то у него, естественно, должен быть и конец. Конец макроопределения определяется оператором MEND. Этот оператор не требует параметров. Макроопределение, взятое в «скобки» MACRO — MEND может располагаться в любом месте исходного модуля, но обычно все макроопределения размещают в начале или в конце модуля.
4
Локальные переменные макроопределения
Поскольку генерация макрорасширения ведется по некоторому алгоритму, описанному в макроопределении, реализация этого алгоритма может потребовать собственных переменных. Эти переменные имеют силу только внутри данного макроопределения, в макрорасширении не остается никаких «следов» переменных макроопределения.
Переменные макроопределения могут использоваться двумя способами:
u их значения могут подставляться вместо их имен в тех операторах макроопределения, которые переходят в макрорасширение;
u их значения могут проверяться в условных операторах макроязыка и влиять на последовательность обработки.
При подстановке значений переменных макроопределения в макрорасширение работают те же правила, что и при подстановки значений параметров.
Для сильносвязанных Макропроцессоров необходимости в локальных переменных макроопределения, вместо них могут использоваться имена программы (определяемые директивой EQU). Для сильносвязанных и независимых процессоров переменный макроопределения и имена программы должны различаться, для этого может применяться тот же признак, что и для параметров макроопределения.
Объявление локальной переменной макроопределения может иметь, например, вид:
имя_переменной LOCL начальное_значение (последнее необязательно)
Присваивание значений переменным макроопределения
Присваивание может
имя_переменной SET выражение
или
имя_переменной = выражение
Выражения, допустимые при присваивании, могут включать в себя имена переменных и параметров макроопределения, константы, строковые, арифметические и логические операции, функции.
Основной тип операций — строковые (выделение подстроки, поиск вхождения, конкатенация. etc.), так как обработка макроопределения состоит в текстовых подстановках.
Строковые операции обычно реализуются в функциях. Однако, в некоторых случаях может потребоваться выполнение над переменными макроопределения операций нестрокового типа.
Как обеспечить выполнение таких операций? Можно предложить два варианта решения этой проблемы:
u Ввести в оператор объявления переменной макроопределения определение ее типа. При выполнении операций должно проверяться соответствие типов.
u Все переменные макроопределения имеют строковый тип, но при вычислении выражений автоматически преобразуются к типу, требуемому для данной операции (при таком преобразовании может возникать ошибка). Результат выражения автоматически преобразуется в строку.