Содержание     Структура модулей Интерфейсная часть Исполняемая часть Инициирующая часть Компиляция модулей  
 

 

Модули

 

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

 

Вполне понятно, поэтому стремление разработчиков коммерческих компиляторов Паскаля включать в язык средства, повышающие его модульность. Чаще всего таким средством является разрешение использовать внешние процедуры и функции, тела которых заменяются зарезервированным словом External.


Разработчики Турбо-Паскаля пошли в этом направлении еще дальше, включив в язык механизм так называемых модулей. Модуль - это автономно компилируемая программная единица, включающая в себя различные компоненты раздела описаний (типы, константы, пе ременные, процедуры и функции) и, возможно, некоторые исполняемые операторы инициирующей части. По своей организации и характеру использования в программе модули Турбо-Паскаля близки к модулям- пакетам (Package) языка программирования Ада: в них также явным образом выделяется некоторая "видимая" интерфейсная часть, в которой сконцентрированы описания глобальных типов, констант и переменных, а кроме того, приводятся заголовки глобальных процедур и функций. Появление объектов в интерфейсной части делает их доступными для других модулей и основной программы. Тела процедур и функций располагаются в исполняемой части модуля, которая может быть скрыта от пользователя.


Насколько сильно изменяются свойства языка Паскаль при введении механизма модулей, свидетельствует следующее замечание его автора Н.Вирта, сделанное им по поводу более позднего языка Модула-2: "Модули - самая важная черта, отличающая язык Модула-2 от его предшественника Паскаля". Кстати, из пяти основных отличий Модулы- 2 от Паскаля, сформулированных Н. Виртом, три: модули, средства программирования низшего уровня и процедурные типы - реализованы в Турбо-Паскале.


Модули представляют собой прекрасный инструмент для разработки библиотек прикладных программ и мощное средство модульного программирования. Важной особенностью модулей является то обстоятельство, что компилятор Турбо-Паскаля размещает их про граммный код в отдельном сегменте памяти. Максимальная длина сегмента не может превышать 64 Кбайт, однако количество одновременно используемых модулей ограничивается лишь доступной памятью, что дает возможность создавать весьма крупные программы.

 

1. Структура модулей

Модуль имеет следующую структуру:
Unit < имя >;
Interface
  < интерфейсная часть >
Implementation
  < исполняемая часть >
[ Begin < инициирующая часть > ]
End.

Здесь:
Unit - кодовое слово (англ. модуль); начинающее заголовок модуля;
<имя> - имя модуля (правильный идентификатор);
Interface - кодовое слово, начинающее интерфейсную часть модуля;
Implementation - кодовое слово (англ. реализация); начинает исполняемую часть;
Begin - кодовое слово, начинающее инициирующую часть;
(часть модуля Begin < инициирующая часть > необязательна);
End. - признак конца модуля.

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

2. Заголовок модуля и связь модулей друг с другом

Заголовок модуля состоит из кодового слова Unit и следующего за ним имени модуля. Для правильной работы среды Турбо-Паскаля и возможности подключения средств, облегчающих разработку крупных программ, это имя должно совпадать, с именем дискового файла, в который помещается исходный текст модуля.

Если, например, имеем заголовок Unit Global, то исходный текст соответствующего модуля должен размещаться в дисковом файле GLOBAL.PAS. Имя модуля служит для его связи с другими модулями и основной программой. Эта связь устанавливается специальным предложением Uses <список модулей>
Здесь:
Uses - кодовое слово (англ. использует);
<список модулей> - список модулей, с которыми устанавливается связь; элементами списка являются имена модулей, отделяемые друг от друга запятыми, например: Uses Crt, Graph, Global;

Если предложение Uses... используется, оно должно открывать раздел описаний основной программы или следовать сразу за кодовым словом Interface в модуле.

3.  Интерфейсная часть

Интерфейсная часть открывается кодовым словом Interface. В этой части содержатся объявления всех глобальных объектов модуля (типов, констант, переменных и подпрограмм), которые должны стать доступными основной программе и/или другим модулям.

При объявлении глобальных блоков в интерфейсной части пишется только их заголовок, например:
Unit Cmplx;
Interface
Type
   Complex = Record
       Re: Real;
       Im: Real;
   End;

Procedure AddC (X, У: Complex; Var R: Complex);
Procedure MulC (X, У: Complex; Var Z : Complex);

Если теперь в основной программе написать предложение Uses Cmplx; то в программе станут доступными тип Complex и две процедуры - Addc и Mulc из модуля Cmplx.

Следует учесть, что все константы и переменные, объявленные в интерфейсной части модуля, равно как и глобальные объекты основной программы, помещаются компилятором Турбо-Паскаля в обилии сегмент данных (максимальная длина сегмента 65521 байт).

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

Если в интерфейсной части объявляются внешние блоки или блоки в машинных кодах, их тела (т.е. зарезервированное слово External в первом случае и машинные коды вместе со словом Inline во втором) должны следовать сразу за их заголовками.

В интерфейсной части модулей нельзя использовать опережающее описание.

4. Исполняемая часть

Исполняемая часть начинается кодовым словом Implementation и содержит тела процедур и функций, объявленных в интерфейсной части. В этой части могут также объявляться локальные для модуля объекты: вспомогательные типы, константы, переменные и блоки, а также метки, если они используются в инициирующей части. Ранее объявленные в интерфейсной части глобальные процедуры и функции должны описываться в той же последовательности, в какой появляются их заголовки в интерфейсной части. Описанию глобального блока в исполняемой части должен предшествовать заголовок, в котором разрешается опускать список формальных переменных (и тип результата для функции), так как они уже описаны в интерфейсной части.

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

Unit Cmplx;
Interface
Type
  Complex = Record
     Re: Real;
     Im: Real;
  End;
Procedure AddC (X, У: Complex; Var Z : Complex);

Implementation

Procedure AddC;
Begin
  Z.Re:= Х.Rе + Y.Re;
  Z.Im:= X.Im + Y.Im;
End;

End.

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

5. Инициирующая часть

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

Unit FileText;
Interface

Procedure Print(S: String);

Implementation
Var
  F: Text;
  Const Name = 'output.txt’;

  Procedure Print;
  Begin
    WriteLn(F, S);
  End;
{ Начало инициирующей части }
Begin
  Assign(F, Name);
  Rewrite(F);
{ Конец инициирующей части }
End.

6. Компиляция модулей

В среде Турбо-Паскаля имеются средства, управляющие способами компиляции модулей и облегчающие разработку крупных программных проектов. В частности, определены три режима компиляции: Compile, Make и Build, Режимы отличаются только способом связи компилируемого модуля или компилируемой основной программы с другими модулями, объявленными в предложении Uses.

При компиляции модуля или основной программы в режиме Compile все упоминающиеся в предложении Uses модули должны быть предварительно откомпилированы и результаты их компиляции должны быть помещены в одноименные файлы с расширением .TPU. Например, если в программе (в модуле) имеется предложение Uses Global, то на диске в каталоге, объявленном опцией Unit directories, уже должен находиться файл GLOBAL.TPU. Файл с расширением .TPU (от англ. Turbo-Pascal Unit) создается в результате компиляции модуля.

В режиме MAKE компилятор проверяет наличие TPU-файлов для каждого объявленного модуля. Если какой-либо из файлов не обнаружен, система пытается отыскать одноименный файл с расширением .PAS, т.е. файл с исходным текстом модуля, и, если PAS- файл найден, приступает к его компиляции. Кроме того, в этом случае система следит за возможными изменениями исходного текста любого используемого модуля. Если внесены какие-либо изменения в PAS-файл (исходный текст модуля), то независимо от того, есть ли уже в каталоге соответствующий TPU-файл или нет, система осуществляет его компиляцию перед компиляцией основной программы.

Более того, если изменения внесены в интерфейсную часгь модуля, то будут перекомпилированы также и все другие модули, обращающиеся к нему. Режим Make, таким образом, существенно облегчает процесс разработки крупных программ с множеством модулей: программист избавляется от необходимости следить за соответствием существующих TPU-файлов и их исходного текста, так как система делает это автоматически.

В режиме Build существующие TPU-файлы игнорируются, и система пытается отыскать (и компилировать) соответствующий PAS-файл для каждого объявленного в Uses модуля. После компиляции в режиме Build программист может быть уверен в том, что учтены все сделанные им изменения в любом из модулей.

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

7. Доступ к объявленным в модуле объектам

Пусть, например, создан модуль, реализующий арифметику комплексных чисел (напомню, что такая арифметика ни в стандартном Паскале, ни в Турбо-Паскале не предусмотрена). К сожалению, в Турбо-Паскале нельзя использовать функции, значения которых имели бы структурированный тип (запись, например), поэтому арифметика комплексных чисел реализуется четырьмя приведенными ниже процедурами.

Unit Cmplx;
Interface
Type
  Complex = Record
      Re: Real;
      Im: Real;
   End;
Procedure AddC (X, У: Complex; Var Z ; Complex);
Procedure SubC (X, У: Complex; Var Z: Complex);
Procedure MulC (X, Y.: Complex; Var Z: Complex);
Procedure DivC (X, У: Complex; Var Z: Complex);

Const
  С: Complex = (Re: 0.1; 1m: -1);

Implementation
  Procedure Addc;
  Begin
    Z.Re:= X.Re + Y.Re;
    Z.Im:= X.Im + Y.Im;
  End {Addc};

  Procedure Subc;
  Begin
    Z.Re:= X.Re - Y.Re;
    Z.Im:= X.Im - Y.Im;
  End {Subc};

   Procedure Mulc;
   Begin
    Z.Re:= X.Re * Y.Re - X.Im * Y.Im;
    Z.Im:= X.Re * Y.Im + X.Im * Y.Re;
  End {Mulc};

  Procedure DivC;
  Var
    ZZ: Real;
  Begin
    ZZ:= Sqr(Y.Re) + Sqr(Y.Im);
    Z.Re:= (X.Re * Y.Re + X.Im * Y.Im) / ZZ;
    Z.Im:= (X.Re * Y.Im - X.Im * Y.Re) / ZZ;
  End;
End.

Текст этого модуля нужно поместить в файл CMPLX.PAS. Теперь можно написать программу, приведенную в примере:

Program TestOfComplex;
Uses Cmplx;
Var
  A, B, С: Complex;
Begin
  A.Re:= 1;
  A.Im:= 1;
  B.Re:= 1;
  B.Im:= 2;
  AddC (A, B, C);
  WriteLn (‘Сложение: ‘, C.Re:5:1, C.Im:5:1,’i’);
  SubC (A, B, C);
  WriteLn (‘Вычитание: ‘, C.Re:5:1, C.Im:5:1,’i’);
  MulC (A, B, C);
  WriteLn ('Умножение: ‘, C.Re:5:1, C.Im:5:1,’i’);
  DivC (A, B, C);
  WriteLn ('Деление: ', C.Re:5:1, C.Im:5:1,’i’);
End.

Как видим, программе стали доступны все объекты, объявленные в интерфейсной части. При необходимости мы можем переопределить любой из этих объектов, как это произошло, например, с объявленной в модуле типизированной константой С. Переопределение объекта означает, что вновь объявленный объект "закрывает" ранее определенный в блоке одноименный объект. При необходимости мы можем получить доступ к "закрытому" объекту. Для этого нужно перед именем объекта поставить имя модуля и точку. Так, оператор
WriteLn(Cmplx.C.Re:5:1, Cmplx.C.Im:5:1,’i’);
выведет на экран содержимое "закрытой" типизированной константы из примера.

8. Стандартные модули

В Турбо-Паскале имеется восемь стандартных модулей, в которых содержится большое число разнообразных типов, констант, процедур и функций. Этими модулями являются: System, Dos, Crt, Printer, Graph, Overlay, Turbo3 и Graph3.

Модули Graph, Turbo3 и Graph3 содержатся в одноименных TPU-файлах, остальные входят в состав библиотечного файла TURBO.TPL. Лишь один модуль System подключается к любой Турбо-Паскалевой программе автоматически, все остальные становятся доступны только после указания их имен в списке, следующем за кодовым словом Uses.

Ниже приводится краткая характеристика стандартных модулей.

В модуль System входят все процедуры и функции стандартного Паскаля, а также встроенные процедуры и функции Турбо-Паскаля, которые не вошли в другие стандартные модули (например, Inc, Dec, Getdir и т.п.). Как уже говорилось, модуль System подключается к любой Турбо-Паскалевой программе независимо от, того, объявлен ли он в предложении Uses или нет.

Модуль Printer упрощает вывод текстов на матричный принтер. В нем определяется файловая переменная Lst типа Text, которая связывается с логическим устройством Prn. После подключения модуля может быть выполнена, например, такая программа:
USES
  Printer;
Begin
  WriteLn (Lst, ‘TEST’); {Выводит строку на принтер}
End.

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

Модуль Graph содержит обширный набор типов, констант, процедур и функций для управления графическим режимом работы экрана. С помощью блоков, входящих в модуль Graph, можно создавать самые разнообразные графические изображения и выводить на экран текстовые надписи стандартными или разработанными программистом шрифтами. Программы модуля Graph после соответствующей настройки могут поддержать любой тип аппаратных графических средств (CGA, EGA, VGA). Настройка на имеющиеся в распоряжении программиста технические средства графики осуществляется специальными программами-драйверами, которые не входят в библиотечный файл TURBO.TPL, но поставляются вместе с ним.

В модуле Dos собраны процедуры и функции, открывающие доступ Турбо-Паскалевым программам ко всем средствам дисковой операционной системы PC DOS (MS DOS).

Блоки модуля Overlay понадобятся при разработке громоздких программ с перекрытиями (позволяет хранить в памяти только нужные части программы, а не требующиеся на данный момент удалять из памяти, сохраняя на диск, либо возвращать в память при необходимости). Как уже говорилось, Турбо-Паскаль обеспечивает создание программ, длина которых ограничивается лишь доступной памятью. Для большинства отечественных IBM-совместимых ПЭВМ доступная программе память составляет около 550 Кбайт (без инстру ментальных оболочек типа Norton Commander и без самой системы Турбо-Паскаль). Память такого размера достаточна для большинства прикладных задач, тем не менее, использование программ с перекрытиями снимает и это ограничение.

Два библиотечных модуля Turbo3 и Graph3 введены для совместимости с ранней версией 3.0 системы Турбо-Паскаль.