В предыдущих примерах рассматривалась программа на языке  ассемблера, используемая совместно с интерпретатором Бейсика.  Версия языка Бейсик, входящая в поставку IBM PC, является  интерпретируемым языком.  Это означает, что программа хранится в  ЭВМ в виде, очень похожем на исходный текст.  Интерпретатор не  преобразует операторы языка Бейсик в команды машинного языка.  Интерпретатор Бейсика во время выполнения просматривает каждый  оператор программы и делает все, что необходимо для выполнения  этого оператора.

По-другому работает компилятор.  Он преобразует операторы языка  высокого уровня в команды машинного языка.  Фирма IBM предлагает  компиляторы для персональной ЭВМ с языков Бейсик, Паскаль, Фортран  и Кобол. Выходом компилятора является программа на машинном языке  (файл *.OBJ), т.е.  он во многом аналогичен выходу ассемблера.  Запуск программы, написанной на компилируемом языке высокого уровня  состоит из двух этапов.  Сначала программа должна быть  скомпилирована, и должны быть отредактированы связи.  Затем она  может быть выполнена.  Интерпретируемая программа может выполняться  непосредственно, минуя этап компиляции.

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

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

Построим пример на языке Фортран (Фиг.  10.11). Для языка  Паскаль все очень похоже.  Подобный пример приведен в приложении D  справочника к компилятору Фортрана.  В примере головная программа,  написанная на Фортране, объединена с программой на языке  ассемблера, которая считывает текущее время, используя программное прерывание базовой системы ввода-вывода.  Подпрограмма на языке  ассемблера обращается к BIOS для определения текущего времени и  возвращает соответствующее значение в программу на Фортране.  Головная программа преобразует кванты таймера, в текущее время,  выраженное в часах, минутах и секундах.

На Фиг. 10.11 представлена головная программа на Фортране.  Эта программа вызывает внешнюю процедуру TIMER, имеющую один  параметр A - четырехбайтовое целое значение.  Возвращаемое процедурой TIMER значение представляет собой текущее время,  выраженное в квантах таймера и отсчитываемое от полуночи.  Программа на Фортране по полученному из процедуры TIMER значению  вычисляет время в часах(HOURS), минутах(MINS), секундах(SECS) и  сотых долях секунды(HSECS).  Отметим, насколько проще реализовать  умножение и деление на языке Фортран, чем на языке ассемблера.  Можно убедиться, что выполнение всех подобных операций на Фортране  существенно упрощает программирование.  Чрезвычайно удобен и способ  преобразования целых переменных в выдаваемые на печать символы при  помощи операторов Фортрана WRITE и FORMAT.  На языке ассемблера для  выполнения тех же самых действий потребовалось бы несколько сот  строк. Вспомним пример для сопроцессора 8087, где программа  преобразовывала число с плавающей точкой в код ASCII.  В этой  программе содержалось значительное число команд, и, кроме того,  использовался сопроцессор 8087.

      $STORAGE=4

            INTEGER A,HOURS,MINS,SECS,HSECS

            CALL TIMER(A)

            HOURS=A/65543

            A=A-HOURS*65543

            MINS=A/1092

            A=A-MINS*1092

            SECS=A/18

            HSECS=(100*(A-SECS*18))/18

            WRITE(*,10)HOURS,MINS,SECS,HSECS

      10    FORMAT(1X,'THE TIME IS: ',I2,':',I2,':',I2,'.',I2)

            END

 

      Фиг. 10.11 Программа определения времени дня на Фортране

 

            Microsoft (R) Macro Assembler Version 5.00                4/2/89 16:07:35

             Фиг. 10.12 Подпрограмма для программы на ФОРТРАНе        Page     1-1

 

                                           PAGE ,132

                                           TITLE      Фиг. 10.12 Подпрограмма для программы на ФОРТРАНе

                                     FRAME      STRUC

             0000      ????              SAVEBP  DW  ?

             0002      ????????          SAVERET DD  ?

             0006      ????????          A    DD   ?          ; Указатель на параметр

             000A                        FRAME      ENDS

 

             0000                        CODE  SEGMENT 'CODE'

                                     DGROUP GROUP    DATA

                                           ASSUME CS:CODE,DS:DGROUP,ES:DGROUP,SS:DGROUP

             0000                        TIMER      PROC FAR

                                           PUBLIC TIMER          ; Указание программе LINK на расположение

                                                             ; программы TIMER

             0000      55                      PUSH  BP

             0001      8B EC                   MOV  BP,SP            ; Загрузка адреса стека

             0003      B4 00                   MOV  AH,0

             0005      CD 1A                   INT  1Ah        ; Вызов BIOS для получения даты и времени

             0007      C4 5E 06                LES  BX,[BP].A  ; Загрузка адреса поля параметров

             000A      26: 89 17               MOV  ES:[BX],DX   ; Сохранение младшей части времени

             000D      26: 89 4F 02                  MOV  ES:[BX+2],CX     ; Сохранение старшей части времени

             0011      5D                      POP  BP

             0012      CA 0004                  RET  4          ; Возврат с удалением параметров из стека

              0015                        TIMER      ENDP

             0015                        CODE  ENDS

                                           END

Фиг. 10.12 Ассемблерная процедура для программы на Фортране

На Фиг. 10.12 представлена подпрограмма на языке ассемблера -  процедура TIMER.  В этой несложной программе для считывания  текущего времени и сохранения полученного значения в двойном слове  используется обращение к BIOS.  Здесь нам необходимо рассмотреть  способ передачи параметров из программы на Фортране в подпрограмму  на языке ассемблера.

На Фиг.10.13 показано содержимое стека в начальный момент  выполнения подпрограммы на языке ассемблера.  Точно так же, как  интерпретатор Бейсика, программа на Фортране помещает адрес  параметра в стек.  Однако компиляторы Фортрана и Паскаля передают  указатель длиной в два слова, а не одно только смещение параметра.  Это означает, что программа на языке ассемблера, прежде чем  получить доступ к параметру, должна установить как сегментный  регистр, так и адрес смещения. Если бы параметров было более  одного, то программа на Фортране перед вызовом поместила бы в стек  значения адресов и остальных параметров.

                       ГДДДДДДДДДДДДґ

                  SPДДДД>і Смещение  і

                       і возврата   і

                       ГДДДДДДДДДДДДґ

                       і Сегмент      і

                       і возврата   і

                       ГДДДДДДДДДДДДґ

                       і Смещение   і

                       і аргумента  і

                       ГДДДДДДДДДДДДґ

                       і Сегмент      і

                       і аргумента  і

                       ГДДДДДДДДДДДДґ

Фиг. 10.13 Стек для вызова процедуры в Фортране

Подпрограмма TIMER на Фиг.  10.12 адресует стек, помещая в него  регистр BP и устанавливая его на вершину стека.Структура FRAME  помогает идентифицировать разные значения в стеке после того как  программа сохранит в нем значение BP.  Команда LES BX,[BP]+A  помещает адрес параметра в пару регистров ES:BX.  Используя этот  адрес, программа помещает четырехбайтовое значение текущего времени  в четырехбайтовую целую переменную.

Заметим, что процедура TIMER извлекает адрес параметра из стека  при выполнении команды возврата точно так же, как это делалось в  программах на языке Бейсик.  Заметим также, что в этой ассемблерной  программе для идентификации имени TIMER используется оператор  PUBLIC. Делается это для того, чтобы редактор связей мог найти  подпрограмму и правильно связать ее с программой на Фортране.  Для  интерпретатора Бейсика такой необходимости не было, поскольку  программа на Бейсике не редактировалась совместно с программой на  языке ассемблера.