Процедуры и функции могут содержать в своих заголовках параметры-переменные (т.е. те, которые передаются как адрес, а не как значение) без указания их типа. Procedure P (Var V1,V2); Через такое объявление можно передавать подпрограммам строки, массивы, записи и т.д. Но при этом процедура (или функция) должна явно задавать тип, к которому внутри нее приравниваются бестиповые переменные.
Традиционное преимущество языка ТР - это использование рекурсии, под которой понимается вызов функции (процедуры) из тела этой же функции (процедуры). Например, вычисление факториала:
Function Fact (n : Word) : LongInt;
begin
if n = 0 then
Fact := 1
else Fact := n * Fact(n-1);
end;
Внесение рекурсивности придает программе изящество, но всегда оно же "заставляет" программы расходовать больше памяти. Дело в том, что каждый "отложенный" вызов подпрограммы это свой набор значений всех локальных переменных этой функции, размещенной в стеке. В ТР размер стека не превышает 64 К.
МОДУЛИ
Стандартный Pascal не предусматривает механизмов раздельной компиляции частей программы с последующей их сборкой перед выполнением. Более того, принцип обязательного описания объекта перед его использованием делает практически невозможным разработку разнообразных библиотек прикладных программ. Точнее, такие библиотеки в рамках стандартного Pascal могут существовать только в виде исходных текстов и программист должен сам включать в программу большие тексты различных поддерживающих процедур (например, процедуры численного интегрирования, математической статистики и т.д.)
Отсюда понятно стремление разработчиков коммерческих компиляторов включать в Pascal средства, повышающие его модульность. В ТР с этой целью включены компоненты, которые так и называются - модули.
Модуль - это автономно компилируемая программная единица, включающая в себя различные компоненты раздела описаний (типы, константы, переменные, процедуры и функции) и, возможно, некоторые исполняемые операторы. Важная особенность модулей заключается в том, что компилятор ТР размещает их программный код в отдельном сегменте памяти. Максимальная длина сегмента не может превышать 64 К, однако количество одновременно используемых модулей ограничивается лишь доступной памятью, что дает возможность создавать весьма крупные программы.
Модуль имеет следующую структуру:
Unit <имя>;
Interface
… {интерфейсная часть}
Implementation
… {выполнение - исполняемая часть}
Begin
… {инициирующая часть}
End.
Т.о. модуль состоит из заголовка и трех составных частей, любая из которых, в принципе, может быть пустой.
Для правильной работы среды ТР имя модуля должно совпадать с именем дискового физического файла, в который помещается исходный текст модуля. Например, модуль с именем Unit Unit_1 размещает свой текст в файле unit_1.pas. Кроме того, имя модуля служит для его связи с другими модулями и основной программой. Эта связь устанавливается специальным предложением:
Uses Unit_1,…;
которое открывает раздел описаний в основной программе, а в других модулях сразу за словом Interface, либо сразу за словом Implementation, либо и там и там (т.е. допускаются два предложения Uses.
В интерфейсной части (за словом Interface) содержатся объявления всех глобальных элементов модуля (типов, констант, переменных, функций, процедур), которые должны стать доступными основной программе и другим модулям, к которым подключен данный модуль. При объявлении глобальных подпрограмм указывается только их заголовок. Например:
Unit Unit_1;
Interface
Type
Complex = record
Re, Im : Real
end;
Var
Zmain : Complex;
Procedure P_1 (X,Y : Complex; Var Z : Complex);
Implementation
Procedure P_1; {сложение двух комплексных чисел}
begin
Z.Re := X.Re + Y.Re;
Z.Im := X.Re + Y.Re
end;
Begin
Zmain.Re := 1; Zmain.Im := -1
End.
Теперь, если в основной программе в разделе Uses есть подключение модуля Unit_1, то в ней будет доступен тип Complex, процедура P_1 и переменная Zmain. Объявление подпрограмм в интерфейсной части автоматически сопровождается их компиляцией с использованием дальней модели памяти. Все константы и переменные, объявленные в интерфейсной части модуля, вместе с глобальными переменными основной программы помещаются компилятором в общий сегмент памяти размером 64 К (65536 байт). В интерфейсной части модуля нельзя использовать опережающее описание. Если при объявлении типов, данных и подпрограмм используются типы и данные, введенные в других модулях, то они должны быть указаны в разделе Uses сразу после слова Interface.
Исполняемая часть (начинается словом Implementation) обычно содержит описания подпрограмм, объявленных в интерфейсной части. В заголовке, предшествующем описанию подпрограммы, можно опустить список формальных параметров (и тип результата для функции), т.к. он был описан в интерфейсной части (см. пример). Часто этим и ограничиваются. Кроме того, в исполняемой части могут объявляться локальные для модуля типы, константы, переменные, подпрограммы, а также метки, если они используются в инициирующей части. Эти типы и данные будут являться глобальными по отношению к подпрограммам этого раздела и операторам раздела инициализации, если он имеется. Естественно, что в программе, которая подключает данный модуль, объявленные в разделе Implementation типы и данные будут недоступны.
Завершает текст модуля раздел инициализации. Если он отсутствует, то просто ставится слово End с точкой. В противном случае он открывается словом Begin, после чего следуют программные действия, которые будут произведены перед выполнением основной программы (работа скомпилированной программы всегда начинается с выполнения блоков инициализации используемых ею модулей, а лишь потом выполняется основной блок самой программы). Обычно в разделе инициализации происходит заполнение стартовыми значениями библиотечных переменных (см. пример) и какие-то одноразовые действия, которые должны выполниться в начале программы (например, открываться нужные файлы и т.д.).
Имеются особенности компиляции модулей. Определены три возможных режима компиляции:
В режиме COMPILE все упоминающиеся в разделе Uses модули должны быть предварительно откомпилированы и результаты компиляции помещены в одноименные файлы с расширением tpu (Turbo Pascal Units) (для нашего примера при компиляции основной программы должен быть файл unit_1.tpu. Такой файл появляется при соответствующей компиляции модуля (по аналогии с компиляцией основной программы, когда появляется исполняемый файл с расширением exe). Используется при отладке основной программы.
В режиме MAKE компилятор проверяет наличие tpu-файлов для каждого объявленного модуля. И если он не обнаружен, то пытается найти одноименный файл с расширением pas, в котором находится исходный текст модуля. Если такой файл найден, то этот модуль компилируется. Кроме того, в этом режиме системы следит за возможным изменением текста модуля. Если он изменялся, то независимо от существования tpu-файлов модуль компилируется заново. Т.о. режим MAKE удобен, т.к. избавляет от необходимости следить за соответствием tpu-файлов исходному тексту. Упрощает процесс обработки многофайловых программ, когда компилируется только необходимый минимум.
В режиме BUILD существующие tpu-файлы игнорируются и система пытается откомпилировать соответствующий pas-файл для каждого модуля. После этого можно быть уверенным, что все изменения внесены.
Первыми подключаются системные модули из библиотеки turbo.tpl, а затем все остальные, хранящиеся в виде tpu-файлов и даже pas-файлов. Если подключаемые модули содержат элементы с одинаковым именем, то обращаться будут к модулю, описанному в разделе Uses последним. Если нужно использовать другие модули, то это нужно указывать при обращении (например, Unit_1.Zmain).
В ТР имеется восемь стандартных модулей, в которых содержится большое число разнообразных типов, констант, процедур и функций. Модули GRAPH, TURBO3, GRAPH3 выделены в отдельные tpu-файлы, а остальные (SYSTEM, DOS, CRT, PRINTER, OVERLAY) входят в состав библиотечного файла turbo.tpl. Лишь один модуль SYSTEM подключается к любой программе автоматически, остальные нужно указывать в разделе Uses.
SYSTEM – включает все стандартные математические процедуры и функции, а также обеспечивает работу с командной строкой, ввод/вывод, эмуляцию сопроцессора, работу с динамической памятью, и т.д.;
DOS – в модуле собраны процедуры и функции, открывающие доступ к средствам ОС МS-DOS, обработка файлов, работа с каталогами;
CRT – содержит библиотеку процедур, которые работают с клавиатурой и дисплеем, обеспечивая текстовый режим работы экрана (просто ввод/вывод м. и без него);
PRINTER – делает доступным вывод текстов на матричный принтер;
GRAPH – содержит обширный набор типов, данных и подпрограмм для управления графическим режимом работы экрана;
OVERLAY – необходим при разработке громоздких программ, длина которых превышает память, отводимую MS-DOS под исполняемую программу (~ 580 Кбайт без учета резидентных программ и самой системы ТР);
TURBO3, GRAPH3 – введены для совместимости с ранней версией 3.0 системы ТР.