Ниже приведена часть грамматики языка, описывающая структуру модуля в языке AlgoPascal. Заглавными буквами обозначены нетерминальные символы, жирным шрифтом обозначены лексемы - ключевые слова, строчными буквами обозначены простые лексемы. Слева от двоеточия стоит нетерминал, справа его значение. В квадратных скобках находится необязательная часть выражения.
UNIT : unit name ";" [DECLARATION_BLOCK] interface INTERFACE_NAMES ";" implementation IMPLEMENTATION_BLOCK end "." DECLARATION_BLOCK : declaration DECLARATION_BODY DECLARATION_BODY : [VAR_BLOCK] DECLARATION_BODY : DECLARATION_BODY FUNCTION_DECL INTERFACE_NAMES : name INTERFACE_NAMES : INTERFACE_NAMES "," name IMPLEMENTATION_BLOCK : implementation IMPLEMENTATION_BODY IMPLEMENTATION_BODY : IMPLEMENTATION_NAMED_VALUES IMPLEMENTATION_BODY : IMPLEMENTATION_BODY FUNCTION_BLOCK IMPLEMENTATION_NAMED_VALUES : [CONST_BLOCK] [VAR_BLOCK]
Итак, попробуем разобраться с тем, что я написал выше. Модуль начинается с ключевого слова unit, за которым идут имя модуля и точка с запятой - совсем, как в Паскале. Но затем идёт пока ещё незнакомый необязательный блок declaration, блок interface приобрёл совсем странный вид - превратился в список имён - а из описания блока implementation следует, что объявлять константы и переменные можно только в самом начале блока, и причём сначала константы, а потом переменные. Как видно, модуль можно поделить на три части: блок declaration, блок interface и блок implementation. Рассмотрим их по очереди, начиная с конца.
Блок implementation играет в алгоритмическом Паскале ту же роль, что и в обычном, хотя его строение и отличается от привычного. В этом блоке можно объявлять константы, переменные и подпрограммы (нетерминал IMPLEMENTATION_NAMED_VALUES объединяет в себе первые два определения, а нетерминал FUNCTION_BLOCK содержит в себе определение подпрограммы). Порядок определения строго фиксирован - сначала определяются константы, затем переменные и только затем определяются подпрограммы.
Блок interface содержит в себе всего лишь список имён. Это имена тех подпрограмм, которые будут доступны извне модуля. В отличие от обычного Паскаля, в алгоритмическом нет опережающих объявлений, каждый идентификатор определяется только один раз, а многопроходный транслятор справляется с использованием ещё не определённых функций и переменных. Переменные нельзя экспортировать напрямую, хотя возможно сделать это с применением функций Get/Set.
Теперь перейдём к новому блоку - declaration. В нём можно объявлять переменные и делать объявления подпрограмм (без тела). Сначала объявляются переменные, затем подпрограммы. В чём же роль этого блока? Этот блок играет две роли - он служит для связывания модуля с другими модулями и для объявления функций, реализация которых не является частью алгоритма. Первая роль не требует долгих объяснений. Если требуется функция из другого модуля, то в этом разделе помещается её объявление и транслятор не будет требовать наличия её реализации в этом модуле. Аналогично, переменные, объявленные здесь, считаются внешними и при трансляции для них не создаются объявления.
Вторая роль несколько специфична и требует подробного рассмотрения. Модуль на языке AlgoPascal можно сравнить с классом, решающим некоторую задачу. Существуют задачи, частью условий которых являются подпрограммы. Скажем, частью условия задачи численного интегрирования или дифференциирования является функция, которую интегрируют или дифференциируют. Эта функция должна быть формально определена, от неё зависит результат алгоритма - но не сам алгоритм. Для того, чтобы транслятор не жаловался на вызов неизвестной функции, в модуле должно быть её объявление. Но нужно ли её определение? Ответ - "нет". Поэтому такие функции можно и нужно помещать в раздел declaration.
Ниже приведены два примера модуля, вычисляющего по определению производную от функции - без использования declaration и с использованием.
unit Differential; interface GetDiff; implementation const DeltaX : Real = 0.0001; function F(X:Real):Real; begin Result := X*X;//заменить на нужную нам функцию end; function GetDiff(X:Real):Real; begin Result := (F(X+DeltaX)-F(X-DeltaX)) / (2*DeltaX); end; end.
unit Differential; declaration function F(X:Real):Real; interface GetDiff; implementation const DeltaX : Real = 0.0001; function GetDiff(X:Real):Real; begin Result := (F(X+DeltaX)-F(X-DeltaX)) / (2*DeltaX); end; end.