Трансляция в Delphi

При трансляции в Delphi транслятор создает файл с именем unitname.pas, где unitname - имя модуля, стоящее после ключевого слова unit. Если воспользоваться меню "Просмотр", то содержимое файла будет открыто в самой программе, без создания файла на диске. Оттранслированный код представляет из себя модуль на языке Delphi. Модуль экспортирует подпрограммы, указанные в разделе interface, локальные подпрограммы не видны вне модуля.

Поскольку функциональность языка AlgoPascal почти полностью включена в Delphi, то проблем с переводом нет. При переводе выражения сохраняют свой вид, код в целом сохраняет свою структуру. Тем не менее, есть небольшое исключение - массивы. Delphi поддерживает динамические массивы, но требует, чтобы нумерация их элементов начиналась с ноля. Поэтому для поддержки требуемой функциональности в версию стандартной библиотеки для языка Delphi включены специальные классы одномерных и двухмерных массивов булевых величин, целых и вещественных чисел.

Для понимания принципов работы полученного кода будет полезно рассмотреть тонкости, возникающие при работе с масивами. Поскольку язык Delphi рассматривает объекты, как указатели на расположенные в памяти данные объекта, то при копировании объектов копируются только указатели, а данные, расположенные в памяти, остаются там, где лежали до этого. Т.е. при передаче переменной в подпрограмму по значению должно произойти копирование переменной, но если передавать по значению объект-массив, то будет скопирован указатель, а не сам объект - а язык AlgoPascal предполагает, что при передаче массивов происходит копирование данных. Поэтому при трансляции в подпрограмму добавляется код, который при входе в неё производит явное копирование тех массивов, которые подпрограмма не имеет права менять. Также перед входом в подпрограмму автоматически вызываются конструкторы для локальных переменных-массивов. А ввиду отсутствия в Delphi автоматического удаления неиспользуемых объектов при выходе из подпрограммы происходит удаление всех созданных внури массивов. Несколько понятнее это станет после примера:

Это код простенькой процедуры на языке AlgoPascal.
Она имеет два параметра-массива (VA - по значению, RA - по ссылке)
и локальную переменную LA.
procedure Passing(VA: array of Real; var RA : array of Real);
var
    LA : array of Real;
    I  : Integer;
begin
    for I:=1 to 10 do
        if I=4 then
            Exit;
end;



А это тот же код после трансляции
procedure Passing(VA : TReal1DArray; var RA : TReal1DArray);
var
    LA : TReal1DArray;
    I : Integer;
label __Finalizing;
begin
    //Initializers
    VA := TReal1DArray.Create(VA);здесь копируется параметр VA
    LA := TReal1DArray.Create;    здесь создается локальная переменная LA

    //Body
    for I:=1 to 10 do
    begin
        if I=4 then
        begin
            goto __Finalizing;вместо выхода - переход на удаление массивов
        end;
    end;

    //Finalizers
__Finalizing:
    VA.Destroy;здесь уничтожаются
    LA.Destroy;локальные данные
end;

Как видно, код несколько разбух за счет добавленных в начале и конце операций с объектами. Но центральная часть кода при трансляции почти не изменилась.

Стандартная библиотека

Стандартная библиотека языка AlgoPascal в Delphi находится в модулях Ap, Array1D и Array2D, расположенных в каталоге StdLib\Delphi. При подключении модулей подключаются стандартные функции и классы динамических массивов. Для поддержки массивов в стандартную библиотеку входят специальные классы: такие, как TReal1DArray, TInteger2DArray, TBoolean2DArray... Думаю, система в наименовании заметна :) Текущая версия стандартной библиотеки поддерживает только одномерные и двумерные массивы.

Как использовать массивы из стандартной библиотеки? Во-первых, массивы одной размерности обладают одинаковым набором методов. Во-вторых, методы массивов разных размерностей отличаются только количеством аргументов, но не типом, а потому можно ограничить рассмотрение только одномерными или двумерными массивами. Рассмотрим двумерные.

TReal2DArray = class
public
    constructor Create();overload;
    constructor Create(Source : TReal2DArray);overload;
    destructor  Destroy;override;
    property    Elements[I, J : Integer]:Real read GetElement write SetElement;default;
    procedure   SetBounds( Low1, High1, Low2, High2 : Integer );
    function    GetHighBound(B : Integer):Integer;
    function    GetLowBound(B : Integer):Integer;
end;

Массив имеет конструктор без параметров для создания пустого массива и конструктор для создания копии массива. При создании массив не имеет размещённых элементов и перед обращением к его элементам необходимо задать границы массива при помощи метода SetBounds. Обращение к элементам массива реализуется через свойство Elements, являющееся свойством "по умолчанию". Приведу пример кода:

procedure P();
var
    A : TReal2DArray;
    B : TBoolean1DArray;
begin
    A := TReal2DArray.Create;
    B := TBoolean1DArray.Create;

    ......

    A.SetBounds(1 , 3 , 1 , 3);
    B.SetBounds(1 , 3);
    B[2] := A[2,1]>A[1,2];

    A.Destroy;
    B.Destroy;
end;