На главную
Подписка
Новости










Главная / MS-DOS / MS-DOS. РУКОВОДСТВО РАЗРАБОТЧИКА / Глава 1 / Синтаксический анализ аргументов макро Сделать домашней страницей Добавить в избранное Написать писмо

НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Синтаксический анализ аргументов макро

С помощью макро, распознающего имена регистров, можно реализовать обобщенное макро PUSH, которое мы назовем @PUSHOP (протолкнуть операнд). (Замечание: мы рассматриваем имя pusha для " протолкнуть все", но PUSHA является кодом операции для чипов 186,188 и 286 фирмы Intel. Использование его для макро может ограничить совместимость снизу вверх. Конечно, Вы всегда можете использовать команду PUSHA в макро pusha для микропроцессоров 8086 и 8088).


Как упоминалось ранее относительно типа операнда, который не определен и не является регистром, необходимо делать некоторые предположения. Для макро @PUSHOP предположим, что неизвестные операнды являются ссылками на непосредственные данные. @PUSHOP ссылается на макро ?reg, и макро ?reg должно быть включено в программу с @PUSHOР. Макро @PUSHOP см. в Листинге 1-10.


@PUSHOP использует возможность макро ?reg различать 16- и 8-битовые регистры. Так как команда PUSH не обрабатывает 8-битовый регистр, для получения первого символа имени регистра используется директива IRPC. Затем @PUSHOP добавляет х, формируя ,таким образом, имя 16-битового регистра, которое приемлемо для PUSH. Заметим, что в этом операторе снова необходимо использование удвоенного амперсанда, причем с обеих сторон формального аргумента, так как сцепление строк возникает с обоих концов.


Для тех случаев, когда предполагается наличие непосредственных данных, вызывается макро @PushIm. Это макро более сложное , чем минимально необходимое, так как предполагается, что для передачи непосредственных данных в стек нельзя использовать регистры. Вместо этого макро использует указатель базы (BP) на адрес стека. После сохранения BP и AX в стеке @PushIm заносит непосредственные данные поверх содержимого AX, обменивая их со старым содержимым BP. После восстановления содержимого BP макро извлекает содержимое AX, выталкивая его из стека. Макро @PushIm приведено в Листинге 1-11.



                   Листинг 1-10. Обобщение макро PUSH - @PushOp
         ----------------------------------------------------------------

            ;; **** @PushOp макро с обобщенным операндом команды PUSH
            ;; Если операнд определен, он может быть:
            ;;              регистром
            ;;              ссылкой на данные
            ;;
            ;; Если операнд не определен, он полагается ссылкой на
            ;;              непосредственные данные
            @PushOp  Macro  arg
                     .SALL
                     IFDEF  &arg                 ;; операнд определен ...
                        ?argtyp = .type &arg           ;; выявить его тип
                        IF     ((?argtyp and 3) EQ 2)  ;;операнд - данные
                          ?argsiz = ((type &arg) + 1)/2 ;; получить длину
                                                        ;; в словах
                          ?argoff = 0          ;; установить смещение в 0
                          REPT   ?argsiz   ;; повторить для каждого слова
                             ?argadd = word ptr &arg + ?argoff ;;получить
                             .XALL                               тип ptr
                             push     ?argadd ;;продв-ть непоср.в память
                             .SALL
                             ?argoff = ?argoff + 2 ;;след-ее слово данных
                           ENDM
                         ENDIF
                         IF ((?argtyp AND 3) EQ 1)  ;;операнд - программа
                           @PushImOff   &arg  ;;продвинуть смещение метки
                         ENDIF
                         IFE    (?argtyp and 3) ;;операнд - абс.значение
                           ?reg &arg
                           IF   (?isr16)        ;;операнд - регистр 16
                             .XALL
                             push        &arg   ;;продвинуть непосред.
                             .SALL
                          ELSE
                            IF  (?isr8)         ;;операнд - регистр 8
                              IRPC chr1,&arg1
                                .XALL
                                push  &&chr1&&x ;;сохранить короткий рег.
                                .SALL
                                EXITM
                                ENDM
                              ELSE            ;;предположить непосред.данные
                                @PushIm &arg  ;;продвинуть непосред. данные
                              ENDIF
                            ENDIF
                          ENDIF
                        ELSE                  ;;продвинуть непосред.данные
                           @PushIm &arg
                        ENDIF
                        ENDM                  ;;конец макроописания
         -----------------------------------------------------------------


            Листинг 1-11. Макро проталкивания непосредственных данных -
                                      @PushIm
         ----------------------------------------------------------------

            ;; **** @PushIm макро проталкивания непосредственных данных
            @PushIm Macro arg
                    .XALL
                    push   bp       ;;сохранить указатель базы
                    mov    bp,sp    ;;переместить указатель стека в BP
                    push   ax       ;;сохранить накопитель
                    mov    ax,&arg  ;;получить непосредственные данные
                    xchg   [bp],ax  ;;обменять старый BP и непосред. данные
                    mov    bp,ax    ;;восстановить старый BP из AX
                    pop    ax       ;;восстановить накопитель
                    .SALL
                    ENDM            ;;конец макроописания
         ----------------------------------------------------------------

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


Для тех случаев, когда делается попытка протолкнуть в стек программные адреса, мы предполагаем, что программист желает сохранить действительное смещение метки. Для проталкивания в стек смещения метки, как непосредственных данных, было использовано макро @PushImOff. Оно отличается от макро @PushIm только использованием команды:


             mov      ax,offset  &arg   ,

что противоположно простому перемещению в макро @PushIm. Макро @PushImOff приведено в Листинге 1-12.


                Листинг 1-12.  Макро  продвижения  в стек смещения
                       непосредственных данных - @PushImOff
         ---------------------------------------------------------------

            ;; **** @PushImOff макро продвижения смещения непосред.данных
            @PushImOff  MACRO  arg
                   .XALL
                   рush    bp       ;;сохранить указатель базы
                   mov     bp,sp    ;;переместить указатель стека в BP
                   push    ax       ;;сохранить накопитель
                   mov     ax,offset &arg ;;получить смещение
                                          ;;непосред.данных
                   xchg    [bp],ax  ;;обменять старый BP и непоср.данные
                   mov     bp,ax    ;;восстановить старый  BP из AX
                   pop     ax       ;;восстановить накопитель
                   .SALL
                   ENDM             ;;конец макроописания
         ----------------------------------------------------------------

Последним дискретным случаем, который распознает @PushOp, является попытка прямого проталкивания в стек данных памяти. Сложность в этом случае заключается в том, что стек воспринимает только 16-битовые данные. Используя директиву перекрытия PTR, можно убедить MASM сохранять нужные данные пословно. @PushOp содержит цикл, который повторяет эту операцию для каждого слова сохраняемых данных, увеличивая адрес на два при каждом проходе цикла. Таким образом можно сохранять в стеке двойные слова, четверные слова, 10-байтовые данные и структуры данных.


Наконец, заметим, что макро @PushOp все еще не обрабатывает ссылки, содержащие сложную адресацию (2[BP] и т.д.). В случае необходимости Вы можете применить подобные проверки, используя макродирективу IRPC для выявления в аргументах квадратных скобок, адресации "база + индекс" и "база + смещение".


Итоговый тест макро @PushOp приведен в Листинге 1-13, который содержит результат нескольких вызовов макро @PushOp.


Последняя операция листинга, где @PushOр обрабатывает 4-словную переменную, не может быть изъята. Каждое проталкивание имеет один и тот же аргумент. Однако из этого красивого листинга не видно, что каждая его строка имеет перемещаемый адрес (0000 для первого слова, 0002 для второго и т.д.). К сожалению, мы не можем в данной книге привести 132-колоночные листинги, и, если Вы хотите проверить, попробуйте получить такой листинг сами.


Этот пример особенно полезен тем, что демонстрирует одну область, где применение макро почти всегда предпочтительнее применения подпрограмм. Что касается обработки стека (как в @PushIm и @PushImOff), макросы способны выполнять эти операции без "угрозы" влияния команды CALL на стек. Это особенно важно при перемещении или изъятии данных из стека, так как подпрограмма не может изменить вершину стека и осуществить возврат, не вызвав серьезных осложнений.


НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Hosted by uCoz