10.7. Компилируемые языки высокого уровня

В предыдущих примерах рассматривалась программа на языке ассемблера, используемая совместно с интерпретатором Бейсика. Версия языка Бейсик, входящая в поставку 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                  1/1/80 04:03:56
Фиг. 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
                                  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. Делается это для того, чтобы редактор связей мог найти подпрограмму и правильно связать ее с программой на Фортране. Для интерпретатора Бейсика такой необходимости не было, поскольку программа на Бейсике не редактировалась совместно с программой на языке ассемблера.