Машинно-независимые особенности макропроцессора 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Машинно-независимые особенности макропроцессора



В этом разделе мы обсудим некоторые расширения описанных выше базовых функций макропроцессора. Как мы уже отмечали, эти расширения не связаны непосредственно с архитектурой машины, для которой создавался макропроцессор. В разд. 4.2.1 описан метод конкатенации параметров макроинструкции с другими строками символов. В разд. 4.2.2 обсуждается один из методов генерации уникальных меток, который позволяет избежать частого использования относительной адресации в теле макроопределения. В разд. 4.2.3 вводится и иллюстрируется на нескольких примерах важное понятие условного макрорасширения (условной макрогенерации). Возможность изменения макрорасширения путем использования управляющих предложений делает макроинструкции существенно более мощным и полезным для программиста средством. В разд. 4.2.4 обсуждается определение и использование ключевых параметров макроинструкций.

 

Конкатенация макропараметров

Большинство макропроцессоров допускает конкатенацию параметров с другими строками символов. Предположим, например, что программа содержит набор переменных с именами ХА1,,ХА2, ХАЗ,..., другой набор переменных с именами ХВ1, ХВ2, ХВЗ,...и т. д. Если над подобными наборами переменных необходимо осуществить одинаковые действия, программист может записать их в виде макроопределения. Его параметр должен так определить необходимый набор переменных (например, А, В и т. д.), чтобы макропроцессор смог, используя значения этого параметра, сконструировать в процессе макрогенерадии все необходимые имена (ХА1, ХВ1 и т. д.).

Предположим, что такой параметр назван &ID. Тело макроопределения может содержать предложение вида

LDA X&IDI

в котором параметр &ID должен быть сконкатенирован со строкой, состоящей из символа X, расположенной до параметра, и со строкой, состоящей из символа 1, расположенной после параметра. Проблема состоит в том, что конец параметра никак специально не обозначен (его начало легко может быть идентифицировано по символу &). Таким образом, рассматриваемое предложение может быть интерпретировано также как строка символов Х, за которой следует параметр &IDI. В данном конкретном случае макропроцессор сможет интерпретировать это предложение правильно. ОДнако если макроопределение содержит в качестве параметров и &ID, и &IDI, то ситуация становится в принципе неразрешимой.

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

 

Генерация уникальных меток

Как мы уже говорили в разд.4.1, тело макроопределения, вообще говоря, не должно содержать обычных меток. Это приводит к необходимости использования в исходной программе относительной адресации. Рассмотрим в качестве примера определение WRBUFF на рис.4.1. Если бы команда TD в строке 135 была помечена, эта метка оказалась бы дважды определенной (для каждой инициализации WRBUFF). Это, естественно, не позволило бы ассемблеру получить готовую программу.

25 RDBUFF MACRO &INDEV,&BUFADR,&RECLTH

30 CLEAR X ОЧИСТКА СЧЕТЧИКА ЦИКЛА

35 CLEAR А

40 CLEAR S

45 +LDT #4096 УСТАНОВКА МАКС. ДЛИНЫ ЗАПИСИ

50 $LOOP TD =X'&INDEV' ПРОВЕРКА ГОТОВНОСТИ УСТРОЙСТВА

55 JEQ $LOOP ЦИКЛ ОЖИДАНИЯ ГОТОВНОСТИ

60 RD =X'&INDEV' ЧТЕНИЕ СИМВОЛА В РЕГИСТР А

65 COMPR A,S ПАРОВЕРКА НА КОНЕЦ ЗАПИСИ

70 JEQ $EXIT ВЫХОД ИЗ ЦИКЛА ЕСЛИ КОНЕЦ ЗАПИСИ

75 STCH &BUFADR,X ЗАПИСЬ СИМВОЛА В БУФЕР

80 TIXR T ЦИКЛ ДО ДОСТИЖЕНИЯ МАКСИМАЛЬНОЙ

85 JLT $LOOP ДЛИНЫ ЗАПИСИ

90 $EXIT STX &RECLTH СОХРАНЕНИЕ ДЛИНЫ ЗАПИСИ

95 MEND

а

 

RDBUFF F1,BUFFER,LENGTH

30 CLEAR X ОЧИСТКА СЧЕТЧИКА ЦИКЛА

35 CLEAR А

40 CLEAR S

45 +LDT #4096 УСТАНОВКА МАКС. ДЛИНЫ ЗАПИСИ

50 $AALOOP TD =X'F1' ПРОВЕРКА ГОТОВНОСТИ УСТРОЙСТВА

55 JEQ $AALOOP ЦИКЛ ОЖИДАНИЯ ГОТОВНОСТИ

60 RD =X'F1' ЧТЕНИЕ СИМВОЛА В РЕГИСТР А

65 COMPR A,S ПАРОВЕРКА НА КОНЕЦ ЗАПИСИ

70 JEQ $AAEXIT ВЫХОД ИЗ ЦИКЛА ЕСЛИ КОНЕЦ ЗАПИСИ

75 STCH BUFFER,X ЗАПИСЬ СИМВОЛА В БУФЕР

80 TIXR T ЦИКЛ ДО ДОСТИЖЕНИЯ МАКСИМАЛЬНОЙ

85 JLT $AALOOP ДЛИНЫ ЗАПИСИ

90 STX &RECLTH СОХРАНЕНИЕ ДЛИНЫ ЗАПИСИ

95 $AAEXIT MEND

б

Рис.4.7. Генерация уникальных меток для макрогенерации.

 

Поскольку строку 135 в этом макроопределении нельзя пометить, в командах перехода на строки 140 и 155 появляются относительные адреса *-3 и *-14. Использование относительной адресации в исходной программе еще может быть приемлемым для коротких переходов типа JEQ *-3. Однако для переходов к далеко расположенным командам подобная запись является неудобной, увеличивает вероятность появления ошибок, трудна для понимания. Многие макропроцессоры решают эту проблему за счет макрогенерации меток специального вида.

Рис. 4.7 иллюстрирует один из способов порождения уникальных меток. Макроопределение RDBUFF изображено на рис. 4.7а. Метки, используемые внутри тела макроопределения, начинаются специальным символом $. На рис. 4.76 изображены предложения макроиницализации и соответствующие им тексты макрорасширений. Все идентификаторы, начинающиеся символом $, модифицированы путем замены символа $ на символы $АА. При обработке других предложений макроинциализа-ции символ $ будет заменен на $ХХ, где XX-двухсимвольный алфавитно-цифровой счетчик количества обработанных предложений макроинициализации. При обработке первого встретившегося в программе предложения макроинициализации XX будет иметь значение АА. При обработке последующих предложений макроинициализации XX будет иметь значения АВ, АС и т. д. (Если для счетчика XX используются только латинские буквы и цифры, то подобный двухсимвольный счетчик позволяет обработать в одной программе до 1296 предложений макроинициализации.) Таким образом, в макрорасширениях, соответствующих различным предложениям макроинициализации, метки будут различаться. Другие примеры будут изображены на рис. 4.8 и 4.10.

Язык ассемблера УУМ допускает появление символа $ в индентификаторах. Однако программисты предупреждаются о том, что этот символ не следует использовать в их программах. Это позволяет избежать всяких конфликтов между идентификаторами программиста и идентификаторами, порожденными макропроцессором.

 

Условные макрорасширения

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

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

На рис. 4.8 приведен пример использования одного из предложений условной макрогенсрации. На рис, 4,8а изображено макроопределение RDBUFF логика и функции которого уже обсуждались. Это макроопределение содержит два дополнительных параметра: &EOR, который определяет шестнадцате-ричный код, являющийся признаком конца записи, и &MAXLTH, который определяет максимальную длину записи, которая может быть прочитана. (Как мы увидим, любой из этих параметров или оба сразу могут быть опущены при инициализации макроса RDBUFF.)

Предложения в строках 44-48 этого макроопределения являются примером простой условной структуры периода макрогенерации. В предложении IF вычисляется булевское выражение, являющееся его операндом. Если значение этого выражения есть TRUE, то порождаются предложения, следующие за предложением IF до тех пор, пока не встретится предложение ELSE. В противном случае эти предложения опускаются и порождаются предложения, следующие за ELSE. Предложение ENDIF завершает условную конструкцию, начатую предложением IF. (Как обычно, альтернатива ELSE может быть опущена.) Таким образом, если значением параметра &MAXLTH является пустая строка (это означает, что соответствующий аргумент был опущен в предложении макроинициализации), то будет порождено предложение в строке 45. В противном случае будет порождено предложение в строке 47.

Аналогичная конструкция содержится в строках 26-28. Обратите внимание, что предложение, следующее за IF, не является строкой, которая должна быть порождена в процессе макрогенерации. Это предложение является директивой макропроцессора (SET), которая присваивает значение 1 переменной &EORCK. Подобные переменные называются переменными периода макрогенерации. Они позволяют хранить нужные значения в период порождения текста макрорасширения. Любой идентификатор, начинающийся символом & и не являющийся параметром макроопределения, является переменной периода макрогенерации. Считается, что начальное значение всех таких переменных равно нулю. Таким образом, если в нашем примере в предложении макроинициализации будет задан аргумент, соответствующий параметру &EOR, то значение параметра &EOR не является пустой строкой, и переменной &EORCK будет присвоено значение 1. В противном случае она сохранит свое исходное значение нуль. Значение этой переменной периода макрогенерации используется в условных структурах в строках с 38 по 43 и с 63 по 73.

В предыдущем примере переменная периода макрогенерации &EORCK использовалась для запоминания результата анализа параметра &EOR (строка 26). В предложениях IF (строки 38 и 63) можно было бы, конечно, вместо использования переменной &EORCK повторить исходное сравнение, в.результате которого это значение было получено.

 

25 RDBUFF MACRO &INDEV,&BUFADR,&RECLTH/&EOR,&MAXLTH

26 IF (&EOR NE ' ')

27 &EORCK SET 1

28 ENDIF

30 CLEAR X ОЧИСТКА СЧЕТЧИКА ЦИКЛА

35 CLEAR А

38 IF (&EORCK EQ 1)

40 LDCH =X'&EOR' УСТАНОВКА СИМВОЛА EOR

42 RMO A,S

44 IF (&MAXLTH EQ ' ')

45 +LDT #4096 МАКСИМАЛЬНАЯ ДЛИНА ЗАПИСИ = 4096

46 ELSE

47 +LDT #&MAXLTH УСТАНОВКА МАКС. ДЛИНЫ ЗАПИСИ

48 ENDIF

50 $LOOP TD =X'&INDEV' ПРОВЕРКА ГОТОВНОСТИ УСТРОЙСТВА

55 JEQ $LOOP ЦИКЛ ОЖИДАНИЯ ГОТОВНОСТИ

60 RD =X'&INDEV' ЧТЕНИЕ СИМВОЛА В РЕГИСТР А

63 IF (&EORCK EQ 1)

65 COMPR A,S ПАРОВЕРКА НА КОНЕЦ ЗАПИСИ

70 JEQ $EXIT ВЫХОД ИЗ ЦИКЛА ЕСЛИ КОНЕЦ ЗАПИСИ

75 STCH &BUFADR,X ЗАПИСЬ СИМВОЛА В БУФЕР

80 TIXR T ЦИКЛ ДО ДОСТИЖЕНИЯ МАКСИМАЛЬНОЙ

85 JLT $LOOP ДЛИНЫ ЗАПИСИ

90 $EXIT STX &RECLTH СОХРАНЕНИЕ ДЛИНЫ ЗАПИСИ

95 MEND

а

 

RDBUFF F3,BUF,RECL,04,2048

30 CLEAR X ОЧИСТКА СЧЕТЧИКА ЦИКЛА

35 CLEAR А

40 LDCH =X'&EOR' УСТАНОВКА СИМВОЛА EOR

42 RMO A,S

47 +LDT #2048 УСТАНОВКА МАКС. ДЛИНЫ ЗАПИСИ

50 $AALOOP TD =X'F3' ПРОВЕРКА ГОТОВНОСТИ УСТРОЙСТВА

55 JEQ $AALOOP ЦИКЛ ОЖИДАНИЯ ГОТОВНОСТИ

60 RD =X'F3' ЧТЕНИЕ СИМВОЛА В РЕГИСТР А

65 COMPR A,S ПАРОВЕРКА НА КОНЕЦ ЗАПИСИ

70 JEQ $AAEXIT ВЫХОД ИЗ ЦИКЛА ЕСЛИ КОНЕЦ ЗАПИСИ

75 STCH BUF,X ЗАПИСЬ СИМВОЛА В БУФЕР

80 TIXR T ЦИКЛ ДО ДОСТИЖЕНИЯ МАКСИМАЛЬНОЙ

85 JLT $AALOOP ДЛИНЫ ЗАПИСИ

90 $AAEXIT STX &RECL СОХРАНЕНИЕ ДЛИНЫ ЗАПИСИ

 

б

 

RDBUFF 0E,BUFFER,LENGTH,,80

30 CLEAR X ОЧИСТКА СЧЕТЧИКА ЦИКЛА

35 CLEAR А

47 +LDT #80 УСТАНОВКА МАКС. ДЛИНЫ ЗАПИСИ

50 $ABLOOP TD =X'0E' ПРОВЕРКА ГОТОВНОСТИ УСТРОЙСТВА

55 JEQ $ABLOOP ЦИКЛ ОЖИДАНИЯ ГОТОВНОСТИ

60 RD =X'0E' ЧТЕНИЕ СИМВОЛА В РЕГИСТР А

75 STCH BUFFER,X ЗАПИСЬ СИМВОЛА В БУФЕР

80 TIXR T ЦИКЛ ДО ДОСТИЖЕНИЯ МАКСИМАЛЬНОЙ

85 JLT $ABLOOP ДЛИНЫ ЗАПИСИ

90 $ABEXIT STX LENGTH СОХРАНЕНИЕ ДЛИНЫ ЗАПИСИ

 

в

 

RDBUFF F1,BUFF,RLENG,04

30 CLEAR X ОЧИСТКА СЧЕТЧИКА ЦИКЛА

35 CLEAR А

40 LDCH =X'04' УСТАНОВКА СИМВОЛА EOR

42 RMO A,S

47 +LDT #4096 УСТАНОВКА МАКС. ДЛИНЫ ЗАПИСИ

50 $ACLOOP TD =X'F1' ПРОВЕРКА ГОТОВНОСТИ УСТРОЙСТВА

55 JEQ $ACLOOP ЦИКЛ ОЖИДАНИЯ ГОТОВНОСТИ

60 RD =X'F1' ЧТЕНИЕ СИМВОЛА В РЕГИСТР А

65 COMPR A,S ПАРОВЕРКА НА КОНЕЦ ЗАПИСИ

70 JEQ $ACEXIT ВЫХОД ИЗ ЦИКЛА ЕСЛИ КОНЕЦ ЗАПИСИ

75 STCH BUF,X ЗАПИСЬ СИМВОЛА В БУФЕР

80 TIXR T ЦИКЛ ДО ДОСТИЖЕНИЯ МАКСИМАЛЬНОЙ

85 JLT $ACLOOP ДЛИНЫ ЗАПИСИ

90 $ACEXIT STX RLENG СОХРАНЕНИЕ ДЛИНЫ ЗАПИСИ

 

г

Рис. 4.8. Использование условных предложений периода макрогенерации

 

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

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

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

Когда в процессе макрогенерации встречается предложение IF, вычисляется соответствующее булевское выражение. Если оно истинно, то макропроцессор продолжает обрабатывать строки из таблицы DEFTAB до тех пор, пока не встретит предложение ELSE или ENDIF. Если встретилось предложение ELSE, то макропроцессор пропускает строки в таблице DEFTAB до предложения ENDIF. После предложения ENDIF макропроцессор продолжает работать в обычном режиме. Если же значение булевского выражения предложения IF ложно, то макропроцессор пропускает строки в таблице DEFTAB до тех пор, пока не встретит ELSE или ENDIF. Далее макропроцессор продолжает работать, как обычно.

Предложенная выше реализация не допускает вложенных конструкций IF. Вы можете подумать о том, как она должна быть изменена, чтобы обрабатывать подобные структуры (см. упр. 4.2.8).

Чрезвычайно важно понять, что проверка истинности булевских выражений в предложениях IF осуществляется на этапе макрогенерации. К началу работы ассемблера все подобные решения уже приняты. Образовалась только одна последовательность предложений готовой программы (например, предложения на рис. 4.8в), а все директивы условной макрогенерации исключены. Таким образом, предложения IF периода макрогенерации дают программисту удобные средства записи различных вариантов своей программы. Эти средства существенно отличны от предложений, подобных COMPR (или предложений IF в языках высокого уровня), которые осуществляют свои проверки во время выполнения программы. То же относится и к присваиванию значений переменным периода макрогенерации и другим директивам условной макрогенерации, которые мы еще обсудим.

Условная конструкция периода макрогенерации IF-ELSE- ENDIF является механизмом, позволяющим однократно перенести или пропустить некоторые строки из тела макроопределения в результирующую программу. На рис. 4.9а приведен пример условных предложений период а макрогенерации другого типа. На нем изображено модифицированное определение макроса RDBLJFF, назначение и функции которого те же, что и раньше. Но с помощью этого макроса программист может определить целый список признаков конца записи. Например, в предложении макроинициализации на рис. 4.96 параметру EOR соответствует список (00, 03, 04). Любой из этих кодов является признаком конца записи. Для упрощения макроопределения параметр &MAXLTH удален; максимальная длина записи всегда полагается равной 4096.

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

 

25 RDBUFF MACRO &INDEV,&BUFADR,&RECLTH,&EOR

27 &EORCK SET %NITEMS(&EOR)

30 CLEAR X ОЧИСТКА СЧЕТЧИКА ЦИКЛА

35 CLEAR А

45 +LDT #4096 МАКСИМАЛЬНАЯ ДЛИНА ЗАПИСИ = 4096

50 $LOOP TD =X'&INDEV' ПРОВЕРКА ГОТОВНОСТИ УСТРОЙСТВА

55 JEQ $LOOP ЦИКЛ ОЖИДАНИЯ ГОТОВНОСТИ

60 RD =X'&INDEV' ЧТЕНИЕ СИМВОЛА В РЕГИСТР А

63 &CTR SET 1

64 WHILE (&CTR LE &EORCT)

65 COMP =X'0000&EOR[&CTR]'

70 JEQ $EXIT

71 &CTR SET &CTR+1

73 ENDW

75 STCH &BUFADR,X ЗАПИСЬ СИМВОЛА В БУФЕР

80 TIXR T ЦИКЛ ДО ДОСТИЖЕНИЯ МАКСИМАЛЬНОЙ

85 JLT $LOOP ДЛИНЫ ЗАПИСИ

90 $EXIT STX &RECLTH СОХРАНЕНИЕ ДЛИНЫ ЗАПИСИ

95 MEND

а

 

 

RDBUFF F2,BUFFER,LENGTH,(00,03,04)

30 CLEAR X ОЧИСТКА СЧЕТЧИКА ЦИКЛА

35 CLEAR А

45 +LDT #4096 МАКСИМАЛЬНАЯ ДЛИНА ЗАПИСИ = 4096

50 $AALOOP TD =X'F2' ПРОВЕРКА ГОТОВНОСТИ УСТРОЙСТВА

55 JEQ $AALOOP ЦИКЛ ОЖИДАНИЯ ГОТОВНОСТИ

60 RD =X'F2' ЧТЕНИЕ СИМВОЛА В РЕГИСТР А

65 COMP =X'000000'

70 JEQ $AAEXIT

65 COMP =X'000003'

70 JEQ $AAEXIT

65 COMP =X'000004'

70 JEQ $AAEXIT

75 STCH BUFFER,X ЗАПИСЬ СИМВОЛА В БУФЕР

80 TIXR T ЦИКЛ ДО ДОСТИЖЕНИЯ МАКСИМАЛЬНОЙ

85 JLT $AALOOP ДЛИНЫ ЗАПИСИ

90 $EXIT STX LENGTH СОХРАНЕНИЕ ДЛИНЫ ЗАПИСИ

б

 

Рис.4.9. Использование предложений условного перехода периода макрогенерации.

 

Примером использования конструкции WHILE-ENDW являются строки 63-73 на рис. 4.9а. Переменной периода макрогенерации &EORCT предварительно (строка 27) было присвоено но значение %NITEMS(&EOR). %М1ТЕМS - это макропроцессорная функция, значением которой является количество элементов в списке, задаваемом в качестве аргумента этой функции. Например, если значение аргумента, соответствующее параметру EOR, есть (00, 03, 04), то значение %NITEMS(&EOR) будет равно 3.

Переменная периода макрогенерации &CTR используется для подсчета того, сколько раз сгенерированы (перенесены из тела макроопределения в результирующую программу) строки, следующие за предложением WHILE. Начальное значение &CTR полагается равным 1 (строка 63) и далее увеличивается на 1 при каждом проходе по циклу (строка 71). Само предложение WHILE говорит о необходимости повтора цикла периода макрогенерации до тех пор, пока значение переменной &CTR меньше или равно значению переменной &EORCT. Это означает, что строки 65-70 будут сгенерированы для каждого элемента списка. Переменная &CTR используется в качестве индекса для выборки соответствующего элемента списка. На первой итерации выражение &EOR [&CTR] в строке 65 будет иметь значение 00, на второй итерации - значение 03 и т.д.

На рис. 4.96 изображено расширение предложения макроинициализации с использованием макроопределения на рис. 4.9а. Вы должны тщательно проанализировать этот пример для того, чтобы убедиться, что вы правильно понимаете смысл предложения WHILE.

Реализация цикла WHILE периода макрогенерации также достаточно проста. Когда макропроцессор встречает предложение WHILE, он вычисляет соответствующее булевское выражение. Если оно ложно, то макропроцессор пропускает строки в таблице DEFTAB до предложения ENDW и продолжает далее работать, как обычно, в режиме безусловной макрогенерации. Если же это выражение истинно, то макропроцессор продолжает обрабатывать строки таблицы DEFTAB обычным образом до предложения ENDW. По предложению ENDW макропроцессор возвращается к предложению WHILE, перевычисляет соответствующее булевское выражение и действует далее в соответствии с этим новым вычисленным значением так, как уже описано.

Предложенный метод реализации не допускает вложенных конструкций WHILE. Вы можете подумать над тем, каким алгоритмом могут поддерживаться такие вложенные конструкции (см. упр. 4.2.12).

Варианты построения макропроцессоров

В этом разделе мы обсудим некоторые базовые варианты построения макропроцессоров. Представленный на распечатке 18 алгоритм не сработает, если внутри тела макроопределения встретится предложение макроинициализации. Часто, однако, желательно использовать макросы именно таким образом. В разд. 4.3.1 изучается эта проблема и предлагаются некоторые пути ее решения.

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

 

10 RDBUFF MACRO &BUFADR, &RECLTH, &INDEF

15.

20. МАКРОС ДЛЯ ЧТЕНИЯ ЗАПИСИ В БУФЕР

25.

30 CLEAR X ОЧИСТКА СЧЕТЧИКА ЦИКЛА

35 CLEAR A

40 CLEAR S

45 +LDT #4096 УСТАНОВКА МАКС. ДЛИНЫ ЗАПИСИ

50 $LOOP RDCHAR &INDEV ПРОВЕРКА ГОТОВНОСТИ УСТРОЙСТВА

65 COMPR A,S ПРОВЕРКА НА КОНЕЦ ЗАПИСИ

70 JЕQ $EXIT ВЫХОД ИЗ ЦИКЛА ЕСЛИ КОНЕЦ ЗАПИСИ

75 STCH &BUFADR,X ЗАПИСЬ СИМВОЛА В БУФEP

80 TIXR Т ЦИКЛ ДО ДОСТИЖЕНИЯ МАКСИМАЛЬНОЙ

85 JLT $LOOP ДЛИНЫ ЗАПИСИ

90 $EXIT SIХ &RECLTH СОХРАНЕНИЕ ДЛИНЫ ЗАПИСИ

95 MEND

а.

 

5 RDCHAR MACRO &IN

10.

15. МАКРОС ДЛЯ ЧТЕНИЯ СИМВОЛА В РЕГИСТР А

20.

25 ТD =X'&IN' ПРОВЕРКА ВХОДНОГО УСТРОЙСТВА

30 JEQ *-3 ЦИКЛ ОЖИДАНИЯ ГОТОВНОСТИ

35 RD =X'&IN' ЧТЕНИЕ СИМВОЛА

40 MEND

б

 

RDBUFF BUFFER,LENGTH,F1

в

ARGTAB: Параметр Значение
  . . BUFFER LENGTH F1 (He используется) . .

 

г

АRGТAВ: Параметр Значение
  . . F1 (He используется) . .

д

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

 

Рекурсивная макрогенерация

На рис. 4.3 был представлен пример определения одной макроинструкции внутри другой. Мы, однако, не встречались с тем, чтобы внутри тела макроопределения были предложения макроинициализации. На рис. 4.11 представлен пример подобного использования макросов. Макроопределение RDBUFF на рис. 4.11а в основном то же, что и на распечатке 16. Для наглядности изменен только порядок параметров. В этом примере мы предполагаем, что макроопределение RDCHAR уже описано. Его функцией является чтение одного символа с заданного устройства в регистр А с учетом необходимых проверок готовности устройства. Соответствующее макроопределение изображено на рис. 4.11б. Использование макроса, подобного RDCHAR, весьма удобно при определении макроса RDBUFF. Оно позволяет программисту при написании макроса RDBUFF не заботиться о деталях управления и доступа к устройству. (Макрос RDCHAR мог быть написан в другое время или даже другим программистом.) Использование такого макроса даст еще большие преимущества на более сложной машине, на которой чтение одного символа осуществляется более длинной и сложнойчем в нашем случае, программой. К сожалению, изложенный выше алгоритм работы макропроцессора не позволяет обрабатывать инициализации макросов внутри других макросов. Предположим, например, что алгоритм на распечатке 18 обрабатывает предложение макроинициализации на рис. 4.11в. После того как предложение макроинициализации будет распознанобудет вызвана процедура EXPANDING. Аргументы из предложения макроинициализации будут помещены в таблицу ARGTAB, как это изображено на рис. 4.11г. Булевской переменной EXPANDING будет присвоено значение TRUE, и начнется процесс макрорасширения. Он будет протекать правильно до строки 50, содержащей инициализацию макроса RDCHAR. В этом месте процедура PROCESSLINE обратится к процедуре EXPAND еще раз. Таблица ARGTAB будет преобразована к виду, представленному на рис. 4.11д. Расширение макроса RDCHAR также осуществится правильно, однако после этого возникнут трудности. По концу макроопределения RDCHAR переменной EXPANDING будет присвоено значение FALSE. Таким образом, макропроцессор "забудет", что он находился в середине процесса макрорасширения, когда встретил предложение инициализации макроса RDCHAR. Кроме того, аргументы первой макроиницмализации (RDBUFF) оказались потерянными, поскольку их значения в таблице ARGTAB затерлись новыми аргументами макроса RDCHAR.

Основной причиной этих трудностей является рекурсивный вызов процедуры EXPAND. Сначала она будет вызвана при обработке предложения макроинициализации макроса RDBUFF. Далее она вызывает процедуру PROCESSLINE (строка 50), которая делает еще одно обращение к EXPAND до возврата из первого вызова этой процедуры. Те же трудности возникнут и с процедурой PROCESSLINE, поскольку она также вызывается рекурсивно. Например, возникает вопрос, куда передавать управление после конца работы процедуры PROCESSLINE: в основной цикл работы макропроцессора или же в цикл внутри процедуры EXPAND.

Эти трудности легко разрешимы, если макропроцессор пишется на языке программирования, допускающем рекурсивные вызовы (таком как Паскаль пли ПЛ/1). Сам компилятор позаботится о том, чтобы значения всех переменных, определенных внутри процедуры, были сохранены при рекурсивном обращении. Компилятор позаботится также и о других деталях обработки рекурсивных вызовов, включая определение адреса возврата из процедуры. (В гл. 5 мы детально обсудим, как компилятор обрабатывает подобные рекурсивные вызовы.) Если же допускающий рекурсию язык программирования недоступен, то программист обязан сам позаботиться о таких вещах, как адрес возврата и значения локальных переменных. В этом случае PROCESSLINE и EXPAND, может быть, вообще не будут оформлены как процедуры. Вместо этого та же логика работы может быть реализована с помощью операторов цикла с хранением значений переменных в стеке. Используемые здесь методы реализации описаны в гл. 5 при обсуждении рекурсии. Пример подобной реализации содержится в работе Донован [ 1972].

 



Поделиться:


Последнее изменение этой страницы: 2017-02-17; просмотров: 198; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.147.58.27 (0.111 с.)