Автор: Пользователь скрыл имя, 10 Марта 2013 в 15:44, курс лекций
Один из основных принципов машины фон Неймана — то, что и программы, и данные хранятся в одной и той же памяти. Сохраняемая в памяти программа представляет собой некоторые коды, которые могут рассматриваться как данные. Возможно, с точки зрения программиста программа — активный компонент, она выполняет некоторые действия. Но с точки зрения процессора команды программы — это данные, которые процессор читает и интерпретирует. С другой стороны программа — это данные с точки зрения обслуживающих программ, например, с точки зрения компилятора, который на входе получает одни данные — программу на языке высокого уровня (ЯВУ), а на выходе выдает другие данные — программу в машинных кодах.
F Блок17: В противном случае заносится новая строка в таблицу локальных имен. В любом случае управление передается на чтение следующей строки макроопределения.
F Блок18: Обработка оператора GLBL отличается от оператора LOCL только тем, что новая строка создается в Таблице глобальных переменных.
F Блок19: При обработке оператора LOCL вычисляется выражение — операнд команды. Вычисление включает в себя подстановку значений входящих в выражение переменных. Возможны ошибки — из-за использования неопределенных имен и ошибок в синтаксисе выражения.
F Блок20: Имя переменной ищется сначала в Таблице локальных переменных.
F Блок21: Если имя найдено, изменяется его значение в Таблице локальных переменных.
F Блок22: Если имя переменной не найдено, оно ищется в Таблице глобальных переменных.
F Блок23: Если имя найдено в Таблице глобальных переменных, изменяется его значение в этой таблице.
F Блок24: Если имя не найдено ни в одной из таблиц, формируется сообщение о неопределенном имени.
F Блок25: При обработке оператора MIF вычисляется условное выражение — 1-й операнд команды (возможны ошибки).
F Блок26: Проверяется значение вычисленного условного выражения.
F Блок27: Если значение выражения «истина», имя метки — 2-го операнда команды ищется в Таблице меток макроопределения.
F Блок28: Если метка найдена в таблице, указатель для следующего чтения из Таблице макроопределений устанавливается на адрес соответствующий метке
F Блок29: Если метка найдена в таблице, выдается сообщение о неопределенной метке.
F Блок30: При обработке оператора MGO имя метки — операнда команды ищется в Таблице меток макроопределения.
F Блок31: Если метка найдена в таблице, указатель для следующего чтения из Таблице макроопределений устанавливается на адрес соответствующий метке.
F Блок32: Если метка найдена в таблице, выдается сообщение о неопределенной метке.
F Блок33: При обработке оператора MNOTE выводится сообщение, определяемое операндом.
F Блок34: Устанавливается и анализируется код серьезности. Код серьезности является общим для всей работы Макропроцессора, его значение изменяется только, если новое значение больше текущего (более серьезная ошибка)
F Блок35: Если код серьезности не допускает продолжения работы Макропроцессора, устанавливается признак завершения работы.
F Блок36: При обработке оператора MEXIT устанавливается и анализируется код серьезности.
F Блок37: Если код серьезности не допускает продолжения работы Макропроцессора, устанавливается признак завершения работы.
F Блок38: Освобождаются структуры данных, созданные для обработки макровызова...
F Блок39: ...и обработка макровызова завершается.
F Блок40: При обработке оператора MEND освобождаются структуры данных, созданные для обработки макровызова...
F Блок41: ...и обработка макровызова завершается.
F Блок42: Любая другая мнемоника операции означает, что оператор является не оператором Макроязыка, а оператором языка Ассемблера. В этом случае прежде всего проверяется, не имеет ли оператор метки, которая должна быть уникальной.
F Блок43: Если оператор имеет такую метку, формируется имя уникальной метки и индекс уникальных меток увеличивается на 1.
F Блок44: Выполняются подстановки в операторе языка Ассемблера (значение имен ищутся в Таблицах локальных и глобальных переменных, возможны ошибки).
F Блок45: Оператор языка Ассемблера записывается в макрорасширение.
4
Библиотеки макроопределений
Макровызовы к макроопределение, приведенному в исходном модуле, могут применяться только в этом же исходном модуле. Для того, чтобы можно было использовать макроопределение в разных исходных модулях, макроопределения помещаются в библиотеку макроопределений. Список библиотек макроопределений, которые используются для данного исходного модуля является параметром Макропроцессора.
Мы в нашей схеме алгоритма показали, что обращение к библиотекам макроопределений происходит на 2-м проходе Макропроцессора — если мнемоника оператора не распознана ни как оператор языка Ассемблера, ни как макрокоманда, определенная в данном исходном модуле. Возможны, однако, и другие алгоритмы использования библиотек.
Один из таких алгоритмов следующий.
Анализ мнемоники производится на 1-м проходе Ассемблера, все операторы, не распознанные как операторы языка Ассемблера, считаются макрокомандами и для них создаются строки в Таблице имен макроопределений.
Если для такой макрокоманды макроопределение еще не найдено, поле ссылки на Таблицу макроопределений остается пустым.
Если в исходном модуле встречается макроопределение, то его текст заносится в Таблицу макроопределений. Если в Таблице имен макроопределений уже есть это имя с пустой ссылкой на Таблицу макроопределений, ссылке присваивается значение. Если такого имени в Таблице имен макроопределений нет, в таблице создается новая строка.
В конце 1-го прохода просматривается Таблица имен макроопределений. Если в таблице находятся имена с пустыми ссылками на Таблицу макроопределений, соответствующее макроопределение ищется в библиотеках. Если макроопределение найдено в библиотеке, его текст переписывается в Таблицу макроопределений и присваивается значение ссылке в соответствующей строке Таблицы имен макроопределений.
Если после этого в Таблице имен макроопределений остаются имена с пустыми ссылками, это свидетельствует об ошибках в программе.
4
Вложенные макровызовы.
Вложенные макроопределения
Можно ли употреблять
макроопределения внутри макроопределений?
Можно ли употреблять макровызовы
вызовы внутри макроопределений? Представленные
выше алгоритмы делать этого не позволяют.
Тем не менее, можно построить
такие алгоритмы
Макроопределения внутри макроопределений
Честно говоря,
необходимость в таких
Против такого средства можно привести 2 соображения:
u макроопределение не бывает слишком большим — иначе не срабатывают его преимущества над подпрограммой (следует однако признать, что могут существовать довольно большие макроопределения, которые генерируют разнообразные варианты небольших макрорасширений);
u в языке Pascal допускаются вложенные процедуры, а в языке C — нет; и C прекрасно обходится без них, да и современная практика программирования на Pascal их практически не использует.
Тем не менее, если вложенные макроопределения все же необходимы, можно предложить следующий вариант их реализации: 1-й проход Макропроцессора работает почти по тому же алгоритму, который приведен нами. Принципиально важно, однако, что Таблица макроопределений и Таблица имен макроопределений имеют последовательную структуру, элементы в них записываются в порядке их поступления.
В Макропроцессоре есть некоторая целая переменная — глубина вложенности. Ее исходное значение — 0, при каждом появлении оператора MACRO это значение увеличивается на 1, при каждом появлении оператора MEND — уменьшается на 1. Если при глубине вложенности 0 появляется оператор MACRO, в Таблицу имен макроопределений заносится новый элемент, и текст макроопределения записывается в Таблицу макроопределений — до тех пор, пока глубина вложенности не станет равной 0.
Появление оператора MACRO при глубине вложенности, большей 0 не приводит к созданию нового элемента в Таблице имен макроопределений.
Таким образом, в Таблице имен макроопределений имеется строка только для самого внешнего макроопределения, а все вложенные пока «не видны» и находятся внутри текста внешнего в Таблице макроопределений.
2-й проход Макропроцессора при обработке макровызова считывает текст макроопределения в некоторый буфер и прежде всего рекурсивно вызывает для его обработки Макропроцессор.
Для вложенного вызова Макропроцессора доступны Таблица макроопределений и Таблица имен макроопределений, новые макроопределения, обнаруженные рекурсивным вызовом заносятся в конец этих таблиц.
При возврате из рекурсивного вызова макроопределения, дописанные им, удаляются из таблиц.
Макрокоманды внутри макроопределений
В отличие от предыдущего, это средство может быть весьма полезным. Прежде всего — для часто употребляемых макрокоманд, могут быть включены в библиотеки макроопределений — системные или пользовательские. Это может весьма упростить создание новых макроопределений.
Для обеспечения такой возможности достаточно сделать рекурсивным только 2-й проход Макропроцессора. В нем несколько усложняется анализ операторов макроопределения. В ветви «Другой» (на нашей схеме алгоритма она начинается с блока) 2-й проход Макропроцессора должен распознавать макрокоманду и, если оператор — макрокоманда, вызывать сам себя. Распознавание макрокоманды — методом исключения: если оператор — не оператор Макроязыка, не директива Ассемблера и не машинная команда, то он считается макрокомандой и ищется в Таблице имен макроопределений. Для рекурсивного вызова создается новая Таблица локальных переменны (и параметров). Таблица глобальных переменных и индекс уникальных меток используются общие.
Некоторая сложность возникает в том случае если вложенные марокоманды — библиотечные. В нашем алгоритме 1-го прохода содержимое макроопределения (то, что лежит между операторами MACRO и MEND) не анализировалось, следовательно, определения вложенных макрокоманд не заносились в Таблицы макроопределений и имен макропредолений. Есть два варианта решения этой проблемы:
u На 1-м проходе все же распознавать вложенные макровызовы и включать макроопределения их в таблицы.
u Выполнять это на 2-м проходе: при появлении оператора, не распознанного ни как оператор Макроязыка, ни как директива Ассемблера, ни как машинная команда и ни как макрокоманда, определение которой уже есть в наших таблицах, считать его библиотечной макрокомандой и искать ее макроопределение в библиотеках. Если макроопределение найдено, оно добавляется в наши таблицы. Нет необходимости удалять из таблиц определение вложенной библиотечной макрокоманды при завершении обработки внешнего макровызова: оно может потребоваться при обработке и последующих макровызовов.
4
Качественное расширение возможностей
Активное и грамотное применение макросредств может сделать работу программиста весьма продуктивной. Так, затратив определенные усилия на создание библиотеки макроопределений, программист может превратить язык Ассемблера в качественно новый язык, который будет обладать некоторыми свойствами языка высокого уровня. Программист может сделать этот язык в известной степени проблемно-ориентированным, то есть в максимальной степени приспособленным для тех задач, которые решает его разработчик. Вкратце опишем те основные направления, по которым может идти расширение возможностей Ассемблера за счет макросредств.
4
Структурный Ассемблер
В виде макрокоманд могут быть реализованы операторы, близкие к операторам управления потоком вычисления в языках высокого уровня (условные операторы, ветвления, различные виды циклов). Известным примером такого расширения является язык Макроассемблера BCPL — предшественник языка C.
4
Объектно-ориентированный
Макросредства могут обеспечить и реализацию свойств объектно-ориентированного программирования — в большей или меньшей степени.
Простейшее расширение Ассемблера ОО свойствами предполагает введение макрокоманды определения объекта (или резервирования памяти для объекта). В макрокоманде указывается тип объекта и она употребляется вместо директив DC/BSS. Для типа могут быть созданы макрокоманды-операции. В этом варианте может быть воплощен принцип полиморфизма, так как одна и та же операция может быть допустимой для разных типов. (Например, одна команда сложения для всех типов — чисел, независимо от из разрядности и формы представления). Принцип инкапсуляции реализуется здесь в том смысле, что программист, использующий макрокоманды не должен знать внутренней структуры объекта и подробности выполнения операций над ним, защиту же внутренней структуры организовать гораздо сложнее.
Имеются примеры разработок, в которых на уровне Макроязыка созданы и средства описания классов, включающие в себя наследование классов со всеми вытекающими из него возможностями.
4
Переносимый машинный язык
Макросредствами может быть обеспечен полнофункциональный набор команд некоторой виртуальной машины. Программа пишется на языке этой виртуальной машины. Для разных платформ создаются библиотеки макроопределений, обеспечивающие расширение макровызовов в команды данной целевой платформы. Программа, таким образом, становится переносимой на уровне исходного текста. Поскольку макроопределение может быть построено так, чтобы генерировать неизбыточный код для каждого конкретного вызова, программа на языке виртуальной машины не будет уступать в эффективности программе, сразу написанной на языке целевого Ассемблера.