Песни о Паскале
Шрифт:
Всё, что размещено в секции интерфейса, называют списком экспорта библиотечного модуля. Таким образом, первичный модуль программы импортирует то, что экспортирует библиотечный модуль, – так налаживается связь между модулями. На рис. 146 показаны окна с файлами нашего проекта: вверху – первичный файл, внизу – файл библиотечного модуля.
Рис.146 –
Компиляция проекта
Теперь все готово для компиляции и запуска нашего проекта. Перейдите в окно первичного модуля и нажмите сочетание Ctrl+F9, – оба файла будут откомпилированы, и программа запустится как обычно. Я не зря прошу перейти в окно именно первичного модуля. Если при нажатии Ctrl+F9 активным будет другое окно, компилятор выдаст обидное сообщение: «Cannot run a unit» – нельзя запустить модуль. В самом деле, модуль – это лишь часть программы, он не может быть исполнен. Компилятор же считает, что в активном окне содержится главная программа и пытается её запустить.
Чтобы не спотыкаться здесь, настройте в IDE имя первичного файла, то есть файла с главной программой, – здесь это «P_59_1». Для этого обратитесь к пункту меню Compile –> Primary file… и укажите там нужный файл (рис. 147). Теперь компилятор будет знать, с какого файла начинать компиляцию. Но и библиотечный файл «MyLibr» он тоже будет обрабатывать всякий раз, когда вы измените в нём что-то, – это очень удобно.
А если начнёте другой проект? Тогда не забудьте сменить имя первичного файла, либо сбросьте это имя через пункт меню Compile –> Clear Primary file.
Рис.147 – Пункты меню для настройки первичного файла
Инициализация модуля
Прежде чем завершить наш многофайловый проект, слегка улучшим его и покажем полные тексты первичного и библиотечного модулей.
Начнем с того, что переменная Stack упоминается в главной программе лишь однажды – при инициализации.
Stack:= nil; { Инициализация стека пустым значением }
Когда-нибудь – в будущих проектах – вы забудете об этой важной мелочи, и наживете несколько часов головной боли. Но, если эту инициализацию перенести в модуль MyLibr, то можно впредь не вспоминать о ней. Для этого создадим в модуле ещё одну секцию – секцию инициализации. Она располагается в модуле последней и открывается ключевым словом BEGIN, вставленным перед завершающим словом END. Между этими словами записывают операторы инициализации, – все это похоже на главную программу в первичном модуле. В нашем случае секция будет такой.
unit MyLibr;
{... }
begin {
Stack:= nil; { Инициализация стека }
end.
Когда сработает эта инициализация? Вы знаете, что стрельба начинается с операторов главной программы в первичном модуле «P_59_1». Это справедливо, пока не подключены библиотечные модули. С ними порядок исполнения программы слегка изменится. Первыми будут выполнены операторы в секциях инициализации подключенных модулей, причем в том порядке, в каком эти модули перечислены в списке USES (если там указано несколько модулей). И лишь затем начнёт выполняться главная программа в первичном модуле. Этот порядок гарантирует компилятор, ваше вмешательство здесь не требуется.
Итак, переместив инициализацию переменной из главной программы в модуль, мы обеспечим её автоматическое выполнение и в будущих проектах. Разумеется, что в главной программе инициализация уже излишня. А раз так, то и переменная Stack с описанием её типа в секции интерфейса уже ни к чему, – вернем все это в секцию реализации. После всех перемещений наш проект обретет окончательный вид.
Внешний библиотечный модуль.
unit MyLibr; { имя библиотечного модуля }
interface { --- секция интерфейса --- }
procedure Push(const arg : string); { заголовок процедуры }
function Pop(var arg : string): boolean; { заголовок функции }
{- – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – - – -}
implementation { --- секция реализации --- }
type PRec = ^TRec; { Тип указатель на запись }
TRec = record { Тип запись для хранения связанных строк }
mStr : string; { хранимая строка }
mNext : PRec; { указатель на следующую запись }
end;
var Stack : PRec; { Голова стека }
{ Процедура размещения строки в стеке }
procedure Push(const arg : string);
var p : PRec;
begin
New(p); { создаем новую переменную-запись }
p^.mStr:= arg; { размещаем строку }
{ размещаем в голове стека }
p^.mNext:= Stack; { указатель на предыдущую запись }
Stack:=p; { текущая запись в голове стека }
end;
{ Процедура извлечения строки из стека }
function Pop(var arg : string): boolean;
var p : PRec;
begin
Pop:= Assigned(Stack); { Если стек не пуст, то TRUE }
{ Если стек не пуст… }
if Assigned(Stack) then begin
arg:= Stack^.mStr; { извлекаем данные из головы стека }
p:= Stack; { временно копируем указатель на голову }
Stack:= Stack^.mNext; { переключаем голову на следующий элемент }