ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.



 

Часть 6


                            Г Л А В А  7
                            ============

                             КОМПИЛЯТОР
                             ==========

         Компилятор JPI  Мodula-2  имеет одно-проходимую структуру,  это значит,  что он выдает
    сгенерированный код одновременно с чтением исходного текста; временные файлы не используют-
    ся.
         Импортирование выполняется рекомпиляцией файлов модулей определений (DEF-файлов), если
    потребуется. Это устраняет необходимость специальных файлов "Таблицы идентификаторов" и оз-
    начает,  что определения модулей не нуждаются в явной компиляции;  они вызывают последующую
    компиляцию, как только будут модифицированы. Это также устраняет ограничения порядка компи-
    ляции, которые обычно соответствуют определениям модулей; реализации модулей могут быть от-
    компилированы в любом порядке.
         Выходом является переместимый обьектный файл  (OBJ-файл)  в  формате  Intel/Microsoft.
    Группа таких файлов собирается в один выполняемый файл (EXE-файл) линкером.

                             OBJ-ФАЙЛЫ
                             =========

         OBJ-файл содержит специальную информацию,  которая упрощает компоновку, проверяет неп-
    ротиворечивость (целостность) и минимизирует размер EXE-файла.
         Записи включения - это вставки, которые сообщают компоновщику имена файлов, используе-
    мых модулем.  Это означает, что только имя главного модуля необходимо определить для компо-
    новки.
         Записи версии - это также вставки, которые записывают дату/время используемых DEF-фай-
    лов.  Компоновщик проверит,  все ли модули соответствуют этим версиям; если нет, появляется
    возможность  фатальной противоречивости,  которая может быть устранена перекомпиляцией (см.
    опцию Make ниже).
         OBJ-файл построен как библиотеки,  что означает,  что модуль разбит на секции, которые
    включаются компоновщиком, если используются. Это устраняет потребность в больших модулях из
    универсальной библиотеки.  Каждая глобальная процедура - это секция сама по себе,  так же и
    группы обьявленных данных, принадлежащие к соответствующим частям VAR или CONST.

                        ПРЕДСТАВЛЕНИЕ ДАННЫХ
                        ====================

         Базисная единица  памяти  - 8-битовый байт.  Каждый обьект Мodula-2 представлен числом
    байтов, определенным его типом. Типы подмножества представляются, как их базовые типы.
         Взятие ADDRESS обьекта дает сброс первого байта его в памяти. Для многобайтовых число-
    вых типов последний значащий байт хранится в младшем адресе.


         Типы CARDINAL представлены двоичными числами без знака:
         SHORTCARD : 1 байт
         CARDINAL  : 2 байта
         LONGCARD  : 4 байта

         Целые типы представлены как двоичные числа с 2-мя дополнениями:
         SHORTINT : 1 байт
         INTEGER  : 2 байта
         LONGINT  : 4 байта

         Тип REAL представлен как пары мантисса/экспонента для процессора 8087 (см. док., отно-
    сящуюся к 8087).
         REAL     : 4 байта
         LONGREAL : 8 байтов

         Перечислимые типы представлены, как двоичное число без знака (перечисление)
         <= 256 значений : 1 байт
         >= 256 значений : 2 байта
         BOOLEAN          : 1 байт
         CHAR             : 1 байт
         Тип "абсолютный указатель" занимает 4 байта,  где первые 2 содержат значение смещения,
    а последние 2 - значения сегмента.  NIL представлен как (0,0). Базовый указатель занимает 2
    байта, содержащих сегмент. Процедурные переменные FAR представлены, как абсолютные указате-
    ли на первый оператор кода процедуры.  Процедурные переменные NEAR представлены как 16- би-
    товые смещения в пределах подходящего сегмента кода.
         Множества представлены упакованной битовой картой с одним битом для  каждого  потенци-
    ального члена элементарного типа,  как указано [0..N].  Число требуемых байтов равно 1 + (N
    DIV 8). Элемент E (0 <= E <= N) представлен битом номер Е MOD 8 в байте номер E DIV 8.
         Элементы массивов  хранятся  в последовательных ячейках памяти и располагаются по воз-
    растанию индексов. Общий размер - это размер элемента, умноженный на число элементов.
         Поля записей также хранятся в последовательных ячейках и в порядке, в котором они опи-
    саны в определении типа; каждое поле хранится согласно своему типу. Общий размер - это сум-
    ма размеров полей.
         Вариантные части имеют особенность: поля различных альтернатив накладываются (совмест-
    ная память) и общий размер вариантной части есть сумма размеров полей большей альтернативы.
         Пример:
         TYPE R = RECORD
                     F1:  INTEGER;               (* Байты 0-1 *)
                     CASE F2: BOOLEAN IS         (* Байт  2   *)
                       | FALSE: F3,              (* Байт  3   *)
                                F4,              (* Байт  4   *)
                                F5: CHAR;        (* Байт  5   *)
                       | TRUE:  F6: CARDINAL     (* Байты 3-4 *)
                     END;
                     F7:  SET OF [0..20];        (* Байты 6-8 *)
                  END; (* SIZE (R) = 9,    VSIZE(R.F6) = 5 *)

                        СОГЛАШЕНИЯ О ВЫЗОВАХ
                        ====================

         Эта часть  требует ознакомления с архитектурой 8086-процессора;  мы будем обращаться к
    регистрам по именам: AX(,AL), BX, CX, DX, SI, DI, BP, SP, CS,SS,DE,ES.


                           Область стека
                           -------------

         Процедура активизации использует аппаратный стек (определенный SS или SP) для несколь-
    ких целей:
         - Передачи параметров.
         - Сохранения адреса возврата.
         - Сохранения регистров, которые используются и должны быть сохранены.
         - Сохранения содержимого 8087-сопроцессора,  если недостаточно стекового  пространства
           8087, и оно оставлено для вспомогательных вычислений с плавающей точкой.
         - Построения таблицы внешних контекстов для доступа к переменным, локальным по отноше-
           нию к близлежащим процедурам.
         - Память для локальных переменных (созданных пользователем либо компилятором).
         - Копии параметров массива открытых значений с тем, чтобы они могли быть модифицирова-
           ны без модификации фактических параметров.
         - Сохранения приоритетов вызывающих процессов.

         Параметры поставляются в стек вызывающими процессами;  остаток строится вызванной про-
    цедурой на входе. Регистр BP указывает на базу стека активизации и используется для доступа
    к локальным переменным и параметрам.
         Общий рисунок имеет вид:





         старый SP ->+--------------------+Высшие адреса
                     :параметры           :Действующие параметры
                     +--------------------+
                     :возврат - CS        :Возвратный сегмент для
                     :                    :FAR
                     :возврат - IP        :Возврат смещения
         новый BP  ->+--------------------+
                     :сохраненный BP      :BP вызывающей программы
                     :таблица BP          :Регистры BP объемлющих
                     :                    :процедур
                     :локальные переменные:Локальные переменные
                     :                    :пользователя
                     :локальные временные :Локальные анонимные
                     :                    :переменные
                     :сохраненные регистры:Регистры вызывающей
                     :                    :программы
                     :копии значений      :Копии массивов парамет-
                     :                    :ров
                     :приоритеты          :Сохраненные приоритеты
                     :                    :(процессов)
                     :сохраненный 8087    :Содержимое 8087 процес-
                     :                    :сора вызывающей про-
                     :                    :граммы
         новый SP  ->+--------------------+Нижние адреса

         Только требуемые части строятся в действительности;  для очень простых процедур доста-
    точно сохранения регистра BP.
         Завершаясь, процедура восстановит стек и сохраненные регистры  (см.  директиву  $C)  в
    состояние, в котором они находились до вызова; это включает освобождение памяти, используе-
    мой параметрами.

                        Передача параметров
                        -------------------

         Параметры выводятся в стек в том порядке, в котором они появляются в объявлении проце-
    дуры.  Конкретно,  что выводится - зависит от типа соответствующего формального параметра и
    является ли он переменной или нет.  Все параметры-переменные и любые открытые массивы пере-
    даются указателем:  передается полный адрес в формате сегмент-смещения, и процедура исполь-
    зует его для доступа в памяти к фактическому параметру. Такой параметр занимает 4 байта вне
    зависимости от типа.
         Переменные параметры,  исключая  открытые массивы,  передаются помещением фактического
    значения параметра в стек.  Занимаемая память задается типом параметра,  исключая тот факт,
    что 1-байтовый тип занимает 2 байта в стеке.
         Для значения параметров открытых массивов процедура (необязательно,  см. директиву $V)
    будет делать копию передаваемого значения в локальной памяти и модифицировать адрес,  пере-
    данный в точку, в копии.
         Для параметров открытых массивов (переменных или нет),  вызывающая процедура будет по-
    мещать (перед адресом) размер (2-байтовый) в байтах фактического массива.

                        Результаты функций
                        ------------------

         Результаты из функций возвращаются разными способами, зависящими от их типа.
         Типы REAL и LONGREAL возвращаются на вершине стека процессора 8087.
         Другие скалярные, небольшие множества, указатели и процедуры-переменные возвращаются в
    регистрах 8086-процессора в зависимости от их размера:  1 байт в AL, 2 байта в AX и 4 байта
    в DX:AX.
         Множества других размеров,  массивы и записи возвращаются в стеке под параметрами: пе-
    ред помещением параметров вызывающая процедура распределяет требуемую память.


                    ОПЦИИ (В КОМАНДНОЙ СТРОКЕ)
                    ==========================

         Вызывая компилятор,  опции определяют, что требуется от него. Они (опции) определяются
    после имени файла при вызове компилятора из командной строки MS-DOS или из меню других опе-
    рационных сред. Например:
                          M2 /C MyMain /ML

         Опции:

         /F - Разрешает, чтобы имена файлов отличались от имен модулей.
         /Н - Использованная совместно с Make (см.  ниже) покажет, какие файлы нужно перекомпи-
    лировать.
         /J - Производит небиблиотечные OBJ - файлы, подразумевая, что все они будут включены в
    процесс компоновки. Это необходимо для некоторых компоновщиков.
         /L - Производит протокол, содержащий информацию о скорости компиляции.
         /М - Вызывает утилиту Маке. Файл, переданный компилятору, должен содержать главный мо-
    дуль и Маке,  основываясь на импорте,  будет искать все модули,  требуемые программой.  Для
    каждого из них проверяется, является ли соответствующий OBJ - файл новым, на основании вре-
    мени и даты,  когда файл использовался. Те, которые необходимо перекомпилировать - переком-
    пилируются. Учитываются только те файлы, чьи модули реализации доступны.
         /N - Включает строки-номера в OBJ - файл. Это позволяет, например, отладчику знать со-
    ответствие между адресами кода и строками исходной программы.
         /D - Запрещает реорганизацию выражений. Это гарантирует подсчет выражений слева напра-
    во, но результат - в неоптимальном коде.
         /Р -  Во  время  компиляции  высвечивает имя текущей процедуры для обозначения течения
    процесса.
         /R - Использованная вместе с Маке,  будет рекомпилировать все, вне зависимости от про-
    верки.  Может быть необходима, поскольку Маке только сравнивает фактическое время/дату фай-
    лов; он не читает OBJ - файлы для поиска записи о версии.
         /V - Делает все переменные изменчивыми: вместо того, чтобы пытаться сохранить перемен-
    ные в регистрах, сохраняет их в памяти. Это может облегчить отладку.


                   ДИРЕКТИВЫ (В ИСХОДНОМ ТЕКСТЕ)
                   =============================

         Директивы, появляющиеся в исходном тексте,  используются для определения различных де-
    талей,  касающихся того, как должен производиться код. Они определены в специальных коммен-
    тариях,  где  первый символ - $.  Каждая директива обозначена одиночной буквой,  за которой
    обычно следует параметр;  несколько директив могут быть даны в одном комментарии, разделен-
    ные запятыми.
         Большинство директив - флажки:  параметр "+" или "-" отмечает,  доступен  признак  или
    нет.  Они  могут быть сброшены до предыдущего значения (перед новой директивой) посредством
    "=".
         Пример:
         (*$V-,M mycod,N*)
         ....
         (*$V=,F*)

         Директивы действительны от места,  где они впервые  встречаются,  до  конца  исходного
    текста или пока не отменится другой директивой текущее.
         Некоторые директивы,  определенные в модуле определений,  отменяют любые назначения  в
    модуле реализации. Это C, G, F, K, N.
         Директивы:
         $A+/- Разрешает (по умолчанию)/запрещает алиасы для глобальных переменных.

         Компилятор будет предполагать,  что переменные, объявленные с заблокированной директи-
    вой, не могут быть доступны прямо и косвенно в одно и то же время.

         $B+/- Включает (по умолчанию)/исключает обработку <УПРСТОП> (Ctrl-Break)  в программе.
    При  включении ее нажатие клавиши <УПР-СТОП> прервет программу;  может динамически включать
    ся/отключаться библиотечными процедурами. Эта директива должна быть в головном модуле.

         $C h Выбирает,  какие регистры будут сохранены процедурами.  Шестнадцатеричный номер h
    определяет регистры:  AX=1,  CX=2, DX=4, BX=8, DS=10, ES=20, SI=40, DI=80. По умолчанию F0=
    DS+ES+SI+DI. BP всегда сохраняется.

         $D n Определяет имя n сегмента (данных),  в который должны помещаться глобальные пере-
    менные,  объявленные в модуле.  По умолчанию используется имя модуля.  В любом случае перед
    именем должно быть D_.  Эта директива должна появиться перед ключевым словом MODULE  как  в
    описательной, так и в исполнительной частях.

         $E+/- Включение/выключение  (по умолчанию) упрощенного обращения к вариантам записи по
    алиасным именам. Вследствие перекрывания компилятор будет нормально считать изменения полей
    вариантных записей, вызывая их в памяти.

         $F Процедуры будут вызываться посредством FAR-вызовов. Также процедурные типы имеют 32
    бит.  Это по умолчанию и относится только к глобальным процедурам. Локальные - всегда NEAR.

         $G+/- Включает (по умолчанию)/выключает префиксы модулей во внешних  именах. Включение
    гарантирует, что внешние имена уникальны.

         $H+/- Включает/выключает (по умолчанию) трактование составных констант как переменных,
    разрешая их модифицирование. Это возможно, поскольку они находятся в памяти.

         $I+/- Включает/выключает (по умолчанию) проверку индекса.  В случае включения, обраще-
    ние к несуществующему элементу массива вызовет ошибку выполнения.  Предполагается,  что все
    переменные имеют разрешенные значения в соответствии с их типом (см.  $R ниже). Также пред-
    полагается, что преобразование типов индексов не вызовет проблем.

         $J+/- Включение/выключение  (по  умолчанию)  процедур прерывания посредством выработки
    возврата IRET вместо обычной команды RET.

         $K+/- Включение/выключение (по умолчанию) соглашения по  вызовам  процедур  для  языка
    "Си". Это определяет, что вызывающая (не вызываемая) процедура убирает параметры и устанав-
    ливает DS-регистр на группу, называемую "DGROUP".

         $M n Определяет имя (n) (кодового) сегмента, в который поместить код. По умолчанию ис-
    пользуется имя модуля. В любом случае имени предшествует С_. Эта директива должна появиться
    до ключевого слова MODULE как в файле определения, так и в исполнительном.

         $N Процедуры будут вызываться вызовами NEAR.  Это требует,  чтобы вызывающие процедуры
    находились в том же сегменте. Также тип процедуры должен быть 16-битовым.

         $O+/- Включает/выключает  (по умолчанию) проверку переполнения по всем числовым опера-
    циям. При включении числовое переполнение вызовет ошибку выполнения.

         $P+/- Включает/выключает (по умолчанию) создание внешних имен для  локальных процедур.
    Включение упрощает отладку, но может вызвать конфликт имен.

         $Q+/- Включает/выключает (по умолчанию) трассировку процедур.  При включении процедуры
    будут выполняться с командой прерывания 60Н на входе и 61Н на выходе. Обработчики этих пре-
    рываний должны быть полностью установлены.

         $R+/- Включает/выключает (по умолчанию) проверку подмножеств. При включении ошибка вы-
    полнения вырабатывается посредством присвоения и передачи параметров, если значение выходит
    за пределы границы типа получателя.

         $S h Определяет размер стека в 16-ричном числе "h" для программы. Эта директива должна
    быть в головном модуле.

         $S+/- Включает/выключает (по умолчанию) проверку переполнения стека. При включении вы-
    рабатывается ошибка выполнения в случае, если исчерпан объем стека.

         $V+/- Включает (по умолчанию)/выключает копирование параметров значений открытого мас-
    сива. Выключение увеличивает эффективность, но потенциально неверно.

         $W+/- Включает/выключает (по умолчанию) изменчивость переменных. Изменчивые переменные
    не содержатся в регистрах операторов.  Это может быть существенно,  если конкурирующие про-
    цессы взаимодействуют посредством разделенных глобальных переменных. Опция командной строки
    /V дублирует эту директиву полностью.

         $X+/- Включает/выключает  (по умолчанию) слежение за процедурами со стороны процессора
    8087. Это необходимо, если вызывающие процедуры вложенных функций исчерпывают стек 8087.

         $Y+/- Включение/выключение (по умолчанию) совпадающих вариантных полей. В случае вклю-
    чения  разрешается использовать одинаковые имена полей в различных вариантных альтернативах
    при условии, что они имеют одинаковый тип и находятся на одинаковом смещении в записи.

         $Z+/- Включение/выключение (по умолчанию) проверки для разыменовывания указателей NIL,
    которые в этом случае вырабатывают ошибку исполнения. Когда директива включена, все локаль-
    ные переменные инициализируются в "0".  Если включение осуществлено в головном модуле,  все
    глобальные переменные обнуляются.


                    ИНТЕРФЕЙС С ДРУГИМИ ЯЗЫКАМИ
                    ===========================

         Поскольку компилятор  производит стандартные OBJ-файлы,  возможно компоновать их с ко-
    дом, написанном на других языках и откомпилированным другими компиляторами.
         Все, что  вызывается из Modula-2,  должно быть объявлено в терминах Modula-2,  так что
    определения модулей (OBJ-файлы) должны быть написаны даже для частей, которые не исполняют-
    ся на языке Modula-2. Но настоящий OBJ-файл вырабатывается другим компилятором.
         Чтобы это работало,  различные части должны согласовываться  по  структуре  выполнения
    всей программы.  Поэтому надо знать структуру выполнения как Modula-2, так и других исполь-
    зуемых языков.
         Просмотр MAP-файлов,  созданных  компоновщиком,  оказывает  большую  помощь при сборке
    фрагментов вместе и просто для понимания.
         Структура выполнения Modula-2 может быть скроена директивами:
         $D - выбор сегмента, куда пойдут данные;
         $M - выбор сегмента, куда пойдет код;
         $G - выключает префикс имени модуля;
         $N - производит процедуры NEAR;
         $F - производит процедуры FAR;
         $C - выбирает, какие регистры сохраняются процедурами;
         $K - следует соглашениям о вызовах языка "Си".

                     Сегменты, группы и классы
                     -------------------------

         Концепция сегмента - фундаментальна для процессора 8086,  и она усовершенствована кон-
    цепциями группы и класса в OBJ-языке.
         Сегмент - это совокупность элементов, чей общий размер меньше, чем 64К. Имеет имя. Лю-
    бой элемент принадлежит одному сегменту.
         Группа - совокупность сегментов,  чем общий размер также меньше 64К.  Также имеет имя.
    Любой сегмент принадлежит одной группе или не принадлежит группе.
         Во время  компоновки множества OBJ-файлов все элементы должны быть упорядочены в физи-
    ческой памяти так, чтобы обеспечить наличие элементов одного сегмента или группы в пределах
    одной области в 64К.
         Сегменты уточняются посредством концепции поименованных классов, которые имеют приори-
    тет  при  упорядочении элементов;  элементы с одинаковым именем класса располагаются по со-
    седству,  в пределах классов элементы из одного сегмента располагаются по соседству. Классы
    имеют приоритет,  так что если 2 элемента имеют одно имя сегмента, но разные имена классов,
    они даже не считаются принадлежащими одному сегменту в 64К.
         Компоновщик согласует классы в порядке, в котором они встречаются во время компоновки.
    Компилятор использует это для достижения правильного расположения памяти в  конечной  прог-
    рамме:  сначала идет код (классы CODE, FCODE), затем глобальные данные (M_DATA), затем сте-
    ковые данные (STACK) и, наконец, динамические данные (HEAP).
         Компилятор для каждого модуля произведет 4 сегмента и одну группу с именами,  получен-
    ными из имени модуля:
         C_module - содержит код для процедур;
         K_module - содержит структурные константы;
         S_module - содержит специальные сегментные константы;
         D_module - содержит глобальные переменные;
         G_module - группа, содержащая С_, К_ и S_сегменты.

         Сегменты могут быть переименованы директивами компилятора:  $D обращаюся к D_сегменту,
    $M к C_,  K_,  S_сегментам и к G_группе. Это позволяет заставить различные модули использо-
    вать одинаковые сегменты:  например, используя (*$D DATA *) во всех модулях можно поместить
    все глобальные переменные в один 64К- байтовый сегмент.
         Следующий сегмент INITCODE содержит инициализационный код для модулей и код для голов-
    ного модуля.  Если (* $M CODE*) определена, INITCODE и C_CODE помещены в группу, называемую
    G_CODE, позволяя всем кодам находиться в пределах одной группы в 64К.
         Поскольку имеется одиночный сегмент данных и группа кодов для каждого модуля, их инди-
    видуальный код и глобальные данные ограничены 64К байтами каждый. Полная группа может иметь
    произвольно большой код и данные.


                        Адресация элементов
                        -------------------

         Физический адрес состоит из двух частей: адрес сегмента и смещение. Все элементы в од-
    ной группе или сегменте имеют один и тот же адрес сегмента, но разные смещения.
         Чтобы адресовать элемент, сегментный регистр должен содержать его адрес сегмента. Этот
    (неявный) регистр объединяется с явным значением смещения, чтобы адресовать элемент. Вызовы
    FAR, с другой стороны, определяют как адрес сегмента, так и смещения явно.
         Таким образом,  отдельные объекты могут быть доступны без перезагрузки сегментного ре-
    гистра, только если они принадлежат одному сегменту или группе. Аналогично, процедура может
    быть  вызвана  только вызовом NEAR,  если вызывающая процедура находится в пределах того же
    кодового сегмента (так, чтобы CS-регистр не нужно было бы изменять).
         Является ли  процедура  NEAR  или  FAR  (директивы $N и $F),  отображается ее командой
    RETurn (возврат) - она не должна ничего делать с сегментом, в котором находится, или с чем-
    нибудь еще в нем.

                        Соглашения об именах
                        --------------------

         Различные OBJ-файлы обращаются к элементам друг друга посредством экспортируемых внеш-
    них имен. Онм могут быть уникальны и определенны.
         Компилятор формирует внешнее имя элемента,  используя в качестве префикса перед именем
    исходного кода имя модуля, в котором он объявлен. Символы $ или @ отделяют эти два имени; $
    для FAR-процедур, @ для NEAR-процедур и данных. Вставку префикса можно отключить директивой
    $G.
         Элементы, объявленные в локальных модулях непосредственно внутри  глобальных  модулей,
    получают префиксами имена как глобальных, так и локальных модулей, разделенных @.
         Пример:

         (*$D XYZ*)
         DEFINITION MODULE M: (* Сегменты C_M, K_M, S_M, D_XYZ *)
           V: INTEGER;   (* Внешнее имя M@V (сегмент D_M)  *)
           PROCEDURE F;  (* Внешнее имя M$F (сегмент С_M)  *)
           (*$N,G-*)
           PROCEDURE N1; (* Внешнее имя N1  (сегмент C_M)  *)
           (*$G+*)
           PROCEDURE N2; (* Внешнее имя M@N2 (сегмент С_М) *)
           (*$F*)
           MODULE L;
             PROCEDURE LP; (* Внешнее имя M@L$LP (сегмент С_М) *)
             .....
           END L;
         END M.


                    ПОДДЕРЖКА СОПРОЦЕССОРА 8087
                    ===========================

         Компилятор вырабатывает команды для сопроцессора 8087 для операций с плавающей точкой.
    Во время выполнения они будут выполняться самим 80x87-чипом или будут эмулированы программ-
    но.
         Эмулятор включается, если любая часть программы использует команды с плавающей точкой.
    Во время выполнения эмулятор проверяет наличие чипа 80х87 и,  если да, перепоправляет вызы-
    вающие эмулятор процедуры к 8087-командам.  Такой же EXEфайл может,  таким образом,  выпол-
    няться на любой машине с максимально возможной скоростью.
         Если известно о наличии 80х87-чипа, для экономии памяти во время компоновки может быть
    предусмотрен пустой эмулятор.  Это сделано путем замещения файла SYSTEM.OBJ OBJ-файлом, ко-
    торый определяет необходимые общие внешние имена в "0";  также должен быть использован дру-
    гой MATHLIB.OBJ. Два таких файла поставляются с расширением .7BJ.
         Обычно особые ситуации для 8087 запрещены.  Программы-обработчики могут быть инсталли-
    рованы (установлены) посредством импортирования модуля FloatExc (см. ГЛАВУ 8).

                       Обработчики прерываний
                       ----------------------

         Возможно написать обработчики прерываний на Modula-2,  хотя не следует пытаться делать
    это без полного понимания процессора 8086 и MS-DOS.
         Обработчик прерывания пишется, как процедура Modula-2; директива $J+ даст ей соответс-
    твующий оператор возврата и директива $C FF заставит сохранить все регистры. Директива $ W+
    может быть использована для сохранения в памяти общих глобальных переменных.
         Аппаратные прерывания  могут  быть  включены/выключены  процедурами  EI и DI из модуля
    SYSTEM.
         Обработчик устанавливается путем назначения его адреса одному из векторов прерываний в
    младших разрядах памяти.
         Пример:

         MODULE Int;
         VAR PrtInt [0:5*4]: ADDRESS;
         (* Прерывание 5: печать экрана. *)
             OldInt:         ADDRESS;
         (*$W+*)
             Flag: BOOLEAN;
         (*$W-*)
         (*$J+,C FF*)
           PROCEDURE Handler;
           BEDIN
             ...
           END Handler;
         (*$J-,C F0*)
         BEGIN
           OldInt := PrtInt;
           PrtInt := ADR(Handler);
           ...
           PrtInt := OldInt;
         END Int.

         Самые предприимчивые  смогут  также писать программы с возможностью прекратиться и ос-
    таться резидентом,  используя вызов MS-DOS 031H. Обработка прерываний должна быть отключена
    ($B-) и стек может быть малым, например, $S 500. Наконец, требования к динамической области
    ЕХЕ-файла должны будут удовлетворены с использованием утилит SETHEAPS;  в противном  случае
    не останется памяти для других программ.




                              Г Л А В А  8
                              ============

                      БИБЛИОТЕКА JPI Modula-2
                      =======================

                              ВВЕДЕНИЕ
                              ========

         Эта глава описывает библиотечные модули, поставляемые с компилятором JPI Modula-2. JPI
    Modula-2 поставляется с 12-ю различными модулями, все вместе содержат 250 процедур.
         Большинство из  этих модулей - это обычные модули,  написанные на языке Modula-2.  Все
    они имеют описательную часть Modula-2, но некоторые из исполнительных написаны на языке Ас-
    семблера.
         Следующие части этой главы описывают каждый модуль в деталях,  но вначале  представлен
    обзор модулей. Описано, также, как обращаться из модуля к модулю.
         Модули могут быть разделены последовательно по более абстрактным функциям,  где каждый
    уровень использует более низкие уровни:

         Уровень        Модуль

         System     :   SYSTEM
         Assembly   :   AsmLib, MATHLIB
         Utility    :   Str,Lib,Storage,Process,Graph,FloatExc
         IO         :   IO, FIO
         Window     :   Window



Яндекс цитирования