Interface {Интерфейсная секция}
{ В этой секции описывается взаимодействие данного модуля с }
{ другими пользовательскими и стандартными модулями, а также }
{ с главной программой. Другими словами – взаимодействие }
{ модуля с «внешней средой». }
USES ИмяДругогоМодуля , … ;{ Список импорта интерфейсной секции }
{ Здесь объявляются модули, средства которых используются в }
{ интерфейсной секции описываемого модуля. }
CONST { Список экспорта интерфейсной секции. Содержит }
TYPE { традиционные разделы Паскаль-программы, в которых }
VAR { определяются константы и типы, а также описываются }
PROCEDURE { переменные и заголовки(!!!) процедур и функций, }
FUNCTION { которые таким образом объявляются доступными }
{ из внешней среды. }
IMPLEMENTATION { Секция реализации }
{ В этой секции описываются данные и действия модуля, }
{ не видимые из вне, в частности, реализация процедур и }
{ функций, объявленных в интерфейсной секции. }
USES ИмяДругогоМодуля , … ; {Список импорта секции реализации. }
{ Здесь объявляются модули, средства которых не используются }
{ явно в интерфейсной секции, но используются в секции }
{ реализации. }
LABEL { Разделы объявления, определения и описания }
CONST { внутренних для секции реализации данных и действий. }
TYPE { Содержит традиционные разделы Паскаль-программы в их }
VAR { традиционном синтаксисе и семантике. }
PROCEDURE { Заголовки процедур и функций, объявленных в }
FUNCTION { интерфейсной секции, здесь можно указать без списка }
{ параметров. }
INITIALIZATION { Секция инициализации – необязательная }
{ В эту секцию включаются действия, которые выполняются }
{ перед выполнением раздела операторов программы, в которой }
{ этот модуль объявлен предложением USES. }
FINALIZATION { Секция завершения – необязательная }
{ В эту секцию включаются действия, которые выполняются по }
{ окончании выполнения раздела операторов программы, в которой}
{ этот модуль объявлен предложением USES. }
END.
Использование модуля.
В оформлении программы (!!! но не описаний процедур и функций) появился новый раздел – список импортируемых модулей:
USES ИмяМодуля , … ;
Этот раздел может отсутствовать, либо должен идти сразу после заголовка программы. Отметим, что другие описательные разделы программы (модулей, процедур и функций) могут следовать в произвольном порядке и даже повторяться (с разным содержанием), но не раздел импортируемых модулей и не раздел операторов.
Имена объектов (типов, переменных, процедур…) модуля, доступные внешней среде, вне модуля используются с уточнением: ИмяМодуля.Имя
Подведем первые итоги.
Синтаксически конструкция описания модуля похожа на конструкцию описания процедуры. Но по сути – существенно отличается:
у модуля нет раздела операторов, который (тело процедуры!!!) играет фундаментальную роль в описании процедуры; секции инициализации и завершения в модуле играют весьма специальную роль подготовки к работе и «чистки рабочего места» по окончании работы;
инструменты, которые модуль предоставляет другим, – константы, типы данных, переменные (для хранения данных), процедуры и функции (для преобразования данных), которые описаны в интерфейсной секции модуля; в традиционной системе понятий языка Паскаль эти переменные, процедуры и т.д. оказались бы локальными и были бы недоступны из вне!!!
Таким образом, понятие интерфейсная секция модуля является принципиально новым понятием, которое «вклинивается» между традиционными понятиями локальные и глобальные объекты.
Модуль не включается в программу как процедура, а используется программой. Модуль является отдельно транслируемой программной единицей, т.е. можно внести изменения в модуль и перетранслировать его, не внося изменений и не перетранслируя использующую его программу, и наоборот.
Поскольку у модулей нет параметров и концепция глобальных объектов для модулей «работает плохо», возникает вопрос о способах организации информационной связи с модулем (и между ними). Как можно организовать использование двумя модулями общих данных и действий? – Через интерфейсную секцию! В частности, можно определить третий модуль, объявив в его интерфейсной секции (доступной «всем желающим») требуемые общие переменные, процедуры и функции, и включить этот модуль в списки импорта в тех модулях, которые «заинтересованы» в этих общих объектах.
ПРИМЕР. В теме «Данные типа ссылка и динамические структуры данных» мы рассматривали однонаправленные линейные списки. Здесь рассмотрим вариант модуля для работы такими списками и пример его использования – построение ряда Фаррея (который мы уже рассматривали в вышеупомянутой теме). PROGRAM\OOP\FARREJ.000\FARREJ.DPR
{Файл UGlob.PAS}
UNIT UGlob; { Это модуль «общих понятий» - для межмодульных связей, }
{ его можно сменить и основной модуль L1List, }
{ не требуя каких либо изменений, будет будет работать }
{ с однонаправленными линейными списками, хранящими не }
{ «числители и знаменатели», а другую информацию. }
INTERFACE
TYPE TVal=RECORD Ch,Zn:INTEGER END;
IMPLEMENTATION
END.
{Файл L1List.PAS}
UNIT L1List; { Это основной модуль примера – вариант инструментария }
{ для работы с однонаправленными линейными списками. }
INTERFACE
USES UGlob;
VAR CurVal:UGlob.TVal; { отсюда можно взять информацию текущего }
{ элемента списка - «числитель и знаменатель» }
PROCEDURE ResetList;
{Текущим устанавливается 1-й элемент списка}
{Его значение засылается в CurVal}
FUNCTION EOList: BOOLEAN;
{Проверяет наличие текущего элемента в списке}
FUNCTION ExistNext: BOOLEAN;
{Проверяет наличие следующего (за текущим) элемента в списке}
PROCEDURE GetNext;
{Текущим устанавливается следующий элемент списка}
{Его значение засылается в CurVal}
PROCEDURE InsPred(ValEl:UGlob.TVal);
{Вставляет перед(!) текущим новый элемент со значением из ValEl }
{!!! текущим остается тот, который был до, но предыдущим - новый}
PROCEDURE WriteAll(VAR TxtF:TextFile);
{Выводит в TxtF все элементы списка}
{!!! TxtF должен быть открыт для записи}
IMPLEMENTATION
TYPE TPElem=^TElem; TElem=RECORD Inf:UGlob.TVal; Next:TPElem END;
VAR PFirst{ссылка на 1-й},PCur{ссылка на текущий},
PPred{ссылка на предшествующий текущему – приходится хранить, }
{т.к. есть желание иметь возможность вставлять новый }
{элемент не после, а перед текущим}:TPElem;
PROCEDURE ResetList; BEGIN PPred:=NIL; PCur:=PFirst;
IF PCur<>NIL THEN CurVal:=PCur^.Inf
END;
FUNCTION EOList; BEGIN EOList:=(PCur=NIL) END;
FUNCTION ExistNext;
BEGIN ExistNext:=(PCur<>NIL)AND(PCur^.Next<>NIL) END;
PROCEDURE GetNext; BEGIN
IF PCur<>NIL THEN BEGIN PPred:=PCur; PCur:=PCur^.Next;
IF PCur<>NIL THEN CurVal:=PCur^.Inf
END
END;
PROCEDURE InsPred; VAR p:TPElem; BEGIN
NEW(p); p^.Inf:=ValEl; p^.Next:=PCur;
IF PPred=NIL THEN PFirst:=p ELSE PPred^.Next:=p; PPred:=p
END;
PROCEDURE WriteAll; VAR p:TPElem; BEGIN p:=PFirst;
WHILE p<>NIL DO BEGIN
WRITE(TxtF,p^.Inf.Ch,':',p^.Inf.Zn,';'); p:=p^.Next
END; WRITELN(TxtF)
END {отметим, что при этом не «сбиты» значения PCur,PPred и т.д.};
INITIALIZATION {список пустой}
PFirst:=NIL;PCur:=NIL;PPred:=NIL;
FINALIZATION
END.
{Файл Farrej.DPR}
{$B-,D+,I+,Q+,R+}
PROGRAM Farrej; { Это программа построения ряда Фаррея F(n), по }
{ алгоритму: F(1) = 0:1,1:1; F(i) строится по F(i-1)}
{ вставками между каждой парой соседних элементов }
{ a:b и c:d, таких что (b+d)=i, нового }
{ элемента (a+c):(b+d). }
USES SysUtils,UGlob,L1List;
VAR PredCur,x:UGlob.TVal; FIn,FOut:TextFile; i,n:INTEGER;
BEGIN x.Ch:=0;x.Zn:=1;L1List.InsPred(x);
x.Ch:=1;{x.Zn:=1;}L1List.InsPred(x) {построили F(1)};
AssignFile(FIn,'FIn.TXT'); RESET(FIn); READ(FIn,n); CloseFile(FIn);
AssignFile(FOut,'FOut.TXT'); REWRITE(FOut); WRITELN(FOut,n);
FOR i:=2 TO n DO BEGIN {Строим F(i)}
L1List.WriteAll(FOut) {протокол для проверки – вывели F(i-1)};
L1List.ResetList {установились на начало списка};
REPEAT PredCur:=L1List.CurVal; L1List.GetNext {получили пару};
IF (PredCur.Zn+L1List.CurVal.Zn)=i THEN BEGIN
x.Ch:=PredCur.Ch+L1List.CurVal.Ch; x.Zn:=i;
L1List.InsPred(x) {вставили новый}
END
UNTIL NOT L1List.ExistNext;
END; L1List.WriteAll(FOut); CloseFile(FOut)
END.