При трансляции в 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;