Заголовок модуля и связь модулей друг с другом
Заголовок модуля состоит из зарезервированного слова UNIT и следующего за ним имени модуля. Здесь же могут присутствовать директивы компилятору, дающие общие установки/соглашения для всего модуля. Для правильной работы среды Турбо Паскаля и возможности подключения средств, облегчающих разработку крупных программ, это имя должно совпадать с именем дискового файла, в который помещается исходный текст модуля. Если, например, имеем заголовок
UNIT Triangle;
то исходный текст соответствующего модуля должен размещаться в дисковом файле TRIANGLE.РАS. Имя модуля служит для его связи с другими модулями и основной программой. Эта связь устанавливается специальным предложением
USES <список модулей>
где USES - зарезервированное слово;
<список модулей> - список модулей, с которыми устанавливается связь; элементами списка являются имена модулей, отделяемые друг от друга запятыми, например:
USES CRT, Grahy, Printer, Triangle;
Интерфейсная часть
Интерфейсная часть открывается зарезервированным словом INTERFACE. В этой части содержатся объявления всех глобальных объектов модуля (типов, констант, переменных и подпрограмм), которые должны стать доступными основной программе и/или другим модулям. При объявлении глобальных подпрограмм в интерфейсной части указывается только их заголовок. Без информации о формальных параметрах блоков нельзя правильно собрать программу из модулей. Кроме того, в интерфейсном разделе могут быть описаныглобальные элементы: константы, переменные, типы, т.е. некоторые элементы, используемые в основной программе и не обязательно используемые в блоках данного модуля. Порядок появления различных разделов объявлений и их количество могут быть произвольными. В интерфейсной части модулей нельзя использовать опережающее описание.
Исполняемая часть
Исполняемая часть начинается зарезервированным словом IMPLEMENTATION и содержит описания подпрограмм, объявленных в интерфейсной части. В ней могут объявляться локальные для модуля объекты - вспомогательные типы, константы, переменные и блоки, а также метки, если они используются в инициирующей части.
Описанию подпрограммы, объявленной в интерфейсной части модуля, в исполняемой части должен предшествовать заголовок, в котором можно опускать список формальных переменных (и тип результата для функции), так как они уже описаны в интерфейсной части. Но если заголовок подпрограммы приводится в полном виде, т.е. со списком формальных параметров и объявлением результата, он должен совпадать с заголовком, объявленным в интерфейсной части.
Локальные переменные и константы, а также все программные коды, порожденные при компиляции модуля, помещаются в общий сегмент памяти.
Инициирующая часть
Инициирующая часть завершает модуль. Она может отсутствовать вместе с начинающим ее словом BEGIN или быть пустой - тогда за BEGIN сразу следует признак конца модуля END.(с точкой).
В инициирующей части размещаются исполняемые операторы, содержащие некоторый фрагмент программы. Эти операторы исполняются до передачи управления основной программе и обычно используются для подготовки ее работы. Например, в них могут инициироваться переменные, открываться нужные файлы, устанавливаться связи с другими ПК по коммуникационным каналам и т.п.
Не рекомендуется делать инициирующую часть пустой, т.к. это может вызвать проблемы при разработке оверлейных программ.
В приведенном ниже примере использования модуля раздел инициализации отсутствует, так как в нем нет необходимости.
Разработка примера модуля
Пример 5.1. Построить модуль Triangle, который можно использовать в разных программах для определения параметров заданного треугольника: площади S, периметра Р, радиусов Rv и Ro вписанной и описанной окружностей. При этом должны быть реализованы четыре варианта исходных данных:
а) заданы три стороны А, В, С;
b) заданы координаты вершин а, b, с треугольника (6 координат);
с) заданы две стороны А, В и угол между ними;
d) задана сторона А и прилежащие углы.
Соответствующие вариантам a – d процедуры обозначим TR_a, TR_b, TR_c, TR_d. Запишем заголовок модуля и интерфейсный раздел.
UNIT TRIANGLE;
INTERFACE
Procedure TR_a (A,B,C:Real;Var S,P,Rv,Ro:Real);
Procedure TR_b (Xa,Ya,Xb,Yb,Xc,Yc:Real; Var S,P,Rv,Ro:Real);
Procedure TR_c (A,B,Ugol:Real; Var S,P,Rv,Ro:Real);
Procedure TR_d (A,Ugol1,Ugol2:Real; Var S,P,Rv,Ro:Real);
{Ниже следует раздел выполнения, использующий известные формулы}
IMPLEMENTATION
Procedure TR_a; {Не нужно повторять описание параметров, если}
Begin {оно было дано в интерфейсном разделе модуля}
Р := (А + В+ 0/2; {Определим Р - полупериметр}
S := Sqrt (Р*(Р-А)*(Р-В)*(Р-0); {Определим S - площадь}
Rv:= S/P; Ro:= A*B*C/(4*S); {Определим окружности Rv и Ro}
Р:= 2*Р; {Вычислим периметр}
End;
Function R(X1,Y1,X2,Y2:Real):Real; {Расстояние между 2 точками}
Begin R:= Sqrt(Sqr(X1-X2) + Sqr(Y1-Y2)) End;
Procedure TR_b:
Var A,B,C:Real;
Begin A:= R(Xa,Ya,Xb,Yb); {Определение длины стороны A}
B:= R(Xa,Ya,Xc,Yc); {Определение длины стороны В}
С:= R(Xb,Yb,Xc,Yc); {Определение длины стороны С}
TR_a(A,B,C,S,P,Rv,Ro) {Обращение к блоку TR_a для}
End; {получения всех искомых величин}
Procedure TR_c;
Var С: Real;
Begin
C:=Sqrt(Sqr(A)+Sqr(B)-2*A*B*Cos(Ugol));
TR_a(A,B,C,S,P,Rv,Ro); {Обращение к блоку TR_a}
End;
Procedure TR_d;
Var B,C,D:Real;
Begin
D:=Sin(pi-UgoH-Ugol2);
B:=A*Sin(Ugol1)/D; {Используем теорему синусов}
C:=A*Sin(Ugol2)/D;
TR_a(A,B,C,S,P,Rv,Ro); {Обращение к блоку TR_a}
End; {После описания конечного блока точка с запятой обязательна}
END. {Закрывающая скобка модуля}
Все четыре варианта вычисления сводятся к операторам, записанным в процедуре TR_a, и в трех случаях предварительно вычисляются недостающие длины сторон треугольника, которые являются локальными переменными, ибо нужны лишь на время работы процедур. В процедуре TR_b используется функция R, вычисляющая расстояние между двумя любыми заданными точками. Функция R скрыта от пользователя: ее заголовок отсутствует в интерфейсном разделе. Поэтому блок R является локальным, местного значения. Блоки TR_a и R размещены так, чтобы в разделе реализации на них можно было ссылаться: сначала идут эти блоки, а ниже - блоки, обращающиеся к ним. Если вы захотите сделать функцию R доступной и для основной программы, занесите заголовок функции R в интерфейсный раздел.
Пример 5.2.Запишем программу, которая с помощью блока из модуля Triangie определяет, какой из двух треугольников abc или def, заданных координатами вершин, имеет наибольшее отношение площади к периметру. Вывод сообщения об этом производится на принтер.
Program Treug; {Заголовок программы обязательно}
Uses Triangle, Printer; {должен быть перед USES !!}
Var Xa,Ya,Xb,Yb,Xc,Yc,Xd,Yd,Xe,Ye,Xf,Yf: Real;
Sabc,Pabc,Sdef,Pdef,Rv,Ro: Real;
BEGIN
Writeln (‘Введите значения координат’);
Readln (Xa,Ya,Xb,Yb,Xc,Yc,Xd,Yd,Xe,Ye,Xf,Yf);
{Здесь программист должен записать операторы для контроля значений}
{исходных данных - координат вершин треугольника}
Write (Lst,’Максимум отношения площадь/периметр’);
Write (Lst, ‘у треугольника’); {Разделена длинная строка}
TR_b (Xa,Ya,Xb,Yb,Xc,Yc,Sabc,Pabc,Rv,Ro);
TR_b (Xd,Yd,Xe,Ye,Xf,Yf,Sdef,Pdef,Rv,Ro);
If (Sabc/Pabc > Sdef/Pdef) Then Writein (Lst, ‘def)
END.
Примечание. Результаты Rv и Ro не нужны, но нельзя сокращать список параметров в процедуре.
Компиляция модулей
В среде Турбо Паскаля имеются средства, управляющие способом компиляции модулей и облегчающие разработку крупных программных проектов. Результатом компиляции модуля является файл с тем же именем и расширением имени .TPU, который заносится на диск, тогда как результат компиляции программы в целом (ЕХЕ-файл) может оставаться в основной памяти. При его получении проверяется правильность обращения к блокам модуля (вот для чего нужна интерфейсная часть).
Общий объем модульной программы может быть много более 64 кбайт, но каждый .TPU-файл не может превышать 64 кбайт. Вызовем подменю COMPILE:
Compile Alt-F9
Make F9
Build
Destination Memory/Disk
Primary file ...
Здесь первые три режима - это режимы компиляции. Они отличаются только способом связи компилируемого модуля или основной программы с другими модулями, объявленными в предложении USES.
При компиляции модуля или основной программы в режиме COMPILE все упоминавшиеся ранее модули в предложении USES должны быть предварительно откомпилированы и помещены в одноименные файлы с расширением TPU.
Если в программе (см. пример 5.2) имеется предложение
USES Triangle, Printer;
где Printer - стандартный модуль, то на диске в каталоге, объявленном опцией UNIT DIRECTORIES, уже должен находиться файл TRIANGLE.TPU. Этот файл создается автоматически в результате компиляции модуля.
В режиме MAKE компилятор проверяет наличие файлов с расширением .TPU для каждого объявленного модуля. Если файл-TPU не обнаружен, то система ищет подобный файл с расширением PAS, т.е. файл с исходным текстом модуля, и при его обнаружении компилирует его. В режиме MAKE система следит за возможными изменениями исходного текста модуля. Если в текст модуля были внесены какие-либо изменения, то система заново его компилирует и только затем приступает к компиляции основной программы. Кроме того, если были внесены изменения в интерфейсную часть модуля, то будут перекомпилированы также и все другие модули, обращающиеся к нему. Таким образом, автоматизация контроля компиляции позволяет значительно снизить нагрузку на программиста при разработке крупных программ с множеством модулей.
Подключение модулей к основной программе и их возможная компиляция осуществляются в порядке их объявления в предложении USES. При переходе к очередному модулю система предварительно отыскивает все модули, на которые он ссылается. Ссылки модулей друг на друга могут образовывать древовидную структуру любой сложности, однако запрещается явное или косвенное обращение модуля к самому себе. Например, недопустимы такие объявления:
Unit A; Unit В;
Interface interface
Uses В; Uses A;
... ...
Implementation implementation
End. End.
Это ограничение можно обойти, если “спрятать” предложение USES в исполняемые части зависимых модулей:
Unit A; Unit В;
Interface Interface
... ...
Implementation Implementation
Uses В; Uses A:
... ...
End. End.
Подобное решение заключается в том, что Турбо Паскаль разрешает ссылки на частично откомпилированные модули. Это эквивалентно опережающему описанию подпрограммы. Если интерфейсные части любых двух модулей независимы, то Турбо Паскаль сможет идентифицировать все глобальные идентификаторы в каждом из модулей, после чего откомпилирует тела модулей обычным способом.