<<< BACK NEXT >>>

МАССИВЫ,  ФАЙЛ-МАССИВЫ  И  РЕГИОНЫ

CAPER предоставляет определенное  разнообразие в организации массивов данных.Массивы CAPER различаются по месту организации: в оперативной памяти или в файле; а так же по способу организации  и  времени жизни: динамически или статически.
   Как правило, мы различаем описание переменной-массива и собственно его, массива, создание. Массивы могут быть описаны в private, local, public и созданы оператором build в необходимой точке программы:

Пример:

private <int> [100,200] arrInt,  =>
        <someStructure> [10, 20, 30 ] arrOfStructures, =>
        <someStructure> [ 3, 2, 2 ] refToArrOfStructures

. . .

build arrInt, arrOfStructures

В то же время, для переменных массивов без указания размерностей позволяется использовать оператор build только в параметризованной форме. Такие переменные служат также для получения указания на уже созданный массив и последующего их использования.

Пример:

private <int> [] aInt,  =>
        <someStructure> [] refToArr

build aInt            ;* вызовет ошибку компиляции
build aInt(10, 20)    ;* корректная форма

build refToArr        ;* вызовет ошибку компиляции
build refToArr(100)( “ABC”, 1, ‘A’ ) ;* корректная форма – будет создан
                                     ;* одномерный массив структур, “ABC”, 1,
                                     ;* ‘A’ – параметры конструктора структуры

Мы можем использовать объявленные переменные в следующих качествах: после построения (см. выше)

   refToArr := arrOfStructures
   refToArr[ 1, 3, 7 ].element += 10  ;* element – определенная компонента
                                      ;* структуры  someStructure

   aInt[10] := refToArr[ 1, 3, 7 ].element ** 2

Обращаем внимание на то, что в первом примере была объявлена переменная refToArrOfStructures, но собственно носитель массива построен не был. Данную переменную можно использовать для хранения указания создаваемых другими способами массивов:
 
   refToArrOfStructures := arrOfStructures

Так как размерности массива для refToArrOfStructures определены, то адресование элементов массива будет формироваться компилятором на основе данных размерностей:

  refToArrOfStructures[ 2, 2, 1 ] будет указывать на элемент
  arrOfStructures[ 10, 1, 1 ]

Тем самым мы можем организовывать локализованное адресование фрагментов массивов. Для создания статичных массивов может быть использован оператор static build и блоки-массивы.

   Динамические массивы могут быть созданы функцией виртуальной машины

   array( < тип >, < инициализатор >, < количество элементов 1>,  .  .  . ,
          < количество элементов N > )

   < тип >  - тип элемента массива.
   < инициализатор > - значение, которым инициализируется массив, или  NULL.

   Значение <инициализатора> должно быть  согласовано с установленным типом. Так, если зафиксирован числовой тип, то инициализатором должно быть число.Если определен строковый тип, то инициализатор должен быть строкой. В этом
случае длина элемента массива определяется длиной инициализирующей строки, включая завершающий  байт с 0x00. Кроме того, инициализатор может быть числом, и тогда это число - длина элемента в байтах. Если типом элемента является "переменная"   или   "место",  то  длина определяется как длина переменной или места. На элементы массива данного типа распространяются все правила работы с переменными и местами. < количество элементов >  - количество элементов в координате массива. Массивы уничтожаются функцией

   DelArray( <указание массива> )
  
(о создании и удалении массивов с помощью операторов BUILD и DELETE см. ниже).

Примеры:

/* Будет создан неинициализированный пятимерный массив целых чисел со знаком
   длинной в слово.
*/
   var1 := array ( 'I', null , 1, 2, 3, 4, 5 )

/* Двухмерный массив беззнаковых полуслов, инициализированных числом 10 */
   var2 := array ( 'H', 10, 2, 3 )

/* Двухмерный массив мест. Каждый элемент массива находится в состоянии
   "свободен"
*/
   var3 := array ( 'P', 10, 2, 3 )

/* Массив строк, инициализированных  "ABC", длина каждого элемента равна 4 */
   var4 := array ( 'S', "ABC" , 3, 4, 5 )

/* Массив 20-ти байтовых элементов */
   var5 := array ( 'S', 20,   3, 4, 5 )

Статические массивы создаются блоками

block <имя блока> as array( <тип>, <инициализатор>, < количество 1>, ... ,
                            <количество N> )
endblock

Элементы массивов адресуются традиционным способом:

  <имя переменной>[ <элемент 1> , <элемент 2> , . . . , <элемент N> ]

< элемент J > - выражение, задающее число. Каждая координата массива адресуется от 1, т.е. первым элементом массива для, например,  var3 является var4[1,1,1], вторым - var4[1,1,2], и т.д., поочередным увеличением координат до значения  var4[3,4,5].
   Так же адресуются и элементы блоков-массивов.
   Если задание < элемент J > не является целым числом, то оно преобразуются в целочисленный тип, причем значение не контролируется на нахождение в диапазоне определения массива. Контроль осуществляется при вычислении абсолютного смещения элемента относительно начала массива. При превышении смещением общего числа элементов массива машиной CAPER выставляется состояние ошибки.

   var3[ 0 , 5 ]  ==  var3[ 1 , 2 ] == var3[ 2 , 0 ]

   Заметим, что элементы массивов именно адресуются. Как правило, внешне это сводится к выбору значения адресуемого элемента, за исключением операции присваивания ":=", по которой осуществляется размещение значения в область элемента массива. Участие элемента массива в вызовах блоков так же сводится к размещению значений элементов массива. Однако в некоторых функциях среды в качестве отдельных параметров передаются именно адреса элементов массивов, а не их значения.
   Для быстрого перемещения по массиву в CAPER введены две операции:
   <> - смещения от элемента массива (левый операнд) на указываемое количество элементов (правый операнд).

   var := arr[5] <> 10
   var := arr[3] <> -3

   Очевидно, что подобные операции чреваты выходом за границы массива с известными последствиям.
   Создание строки (и массива одновременно) осуществляется функцией

   String( <длина строки> [, <символ заполнения> ] )

<длина строки> - число; выделяется память <длина строки> + 1; последний байт заполняется нулем.
<символ заполнения> - байтовая переменная или литерал.

   var := string( 10, ‘a’ )

Здесь десять байтов будут заполнены символом ‘a’, 11-ый бай – 0. Удаление строки реализуется

   DelString( <указание строки> )

Для переменной var, хранящей указание строки (см. выше), это
 
   DelString( var )

   В языке CAPER введено понятие файл-массива - инструмента управления файлами фиксированной длины таким же способом, как и массивами.

   farray( < указание файла > , < тип > , < инициализатор >,
           < количество элементов 1>,  .  .  . ,  < количество элементов N > )

   < указание файла > - строка указания файла (имя файла).

Все остальные параметры имеют то же значение, что и в функции array.
   Поведение данной функции зависит от комбинации параметров. Обязательным является первый параметр. Если файл существует, то файл воспринимается как одномерный массив с длиной, равной длине файла и типом элемента  'B' (байт). В случае отсутствия файла farray при единственном параметре порождает состояние ошибки.
   Добавление к параметрам указателя типа вызовет такую же интерпретацию с единственным отличием - типом элемента. Наличие инициализатора приведет к перезаписи содержимого файла инициализирующим значением.
   Наконец, наличие значений измерений файл-массива  интерпретируется следующим образом: если файл существует, то при наличие инициализатора та часть, которая охватывается измерениями массива, будет перезаписана, если же файла нет, то он создается с указанным именем и длиной, определенной размерностям, и инициализируется. Отметим, что файл-массив может охватывать не весь файл, а только его начальную часть.

Примеры:

   public  var1, var2, var3, var4

   var1 :=  farray(  "e:\CAPER3\Data\file1.arr" ) ;* файл  
   "e:\CAPER3\Data\file1.arr"                     => должен существовать
   var2 :=  farray(  "e:\CAPER3\Data\file1.arr", 2 )

   private i := 9, j

   var1[ i ] := 'O',   var1[  i +1 ] := 'k'
*    var2[ 5 ]   -  2  байта,  содержащие  "Ok"
*    var2[ 5 ] [1]   == 'O,   var2[ 5 ] [ 2 ]  == 'k'
   var3 := array( 'B', 100 )

*    Значение в var3[  1 ]  ==  79  ( десятичное значение ASCII-кода =>
     латинской буквы ‘O’ )
   var3[ 1 ] := var2[ 5 ]
   var4 := farray(  "e:\CAPER3\Data\file2.arr" , 'H',  null , 640, 480 )

/*
     file2.arr  может  не существовать, тогда он будет создан размером 
     2 * 307200 ;
     если файл длиннее, то файл-массивом адресуются первые 307200  полуслов,
     если короче, то при  адресовании более  "далекого"  элемента в файле
     произойдет ошибка в момент доступа к данному элементу.
*/

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

   places  pLVar1, pLVar2
   pLVar1 := farray(  "e:\CAPER3\Data\file2.arr" , 'W',  null , 320, 240 )

   flock( @pLVar1,  READ_ONLY  )
     .  .  .
   pLVar1[ 1,1 ]  := 0    ;*   вызовет установку состояния ошибки.

Так же при

   flock( @pLVar1,  WRITE_ONLY  )
   intVar  := pLVar1[ 1,1 ]  ;*  есть блокировка по чтению

Однако ничто не запрещает создание другого файл-массива

   pLVar2  := farray(  "e:\CAPER3\Data\file2.arr" , 'W',  null , 320, 240 )

и манипуляцию его элементами без ограничений:  pLVar2 - открытое место. Особое место в системе массивов CAPER занимают массивы переменных и мест. Так, допустимы:

   var1 := array('H', null, 20,30,40)
   .  .  .
   var2 := array( 'P',  null, 10, 20 )
   var2[ 2, 3 ] := var1
   pLVar2  := farray(  "e:\CAPER3\Data\file2.arr" , 'W',  null , 320, 240 )
   var2[ 2, 4 ] := pLVar2

или непосредственно

   var2[ 2, 4 ] := farray(  "e:\CAPER3\Data\file2.arr", 'W', null, 320, 240 )

Разрешено:

   var2[ 2, 4 ] [  10 , 30 ]    - указывает  на элемент  файл-массива.
   var2[  3 ,  4 ]  := getAddr(  "BlockName"  )

/*
     функция getaddr  возвращает внутренний адрес первой команды блока, что
     позволит инициировать вызов блока по данному адресу:
     do  &var2[  3 ,  4 ]( param1, param2 )
     или
     var := var2[ 3 , 4 ]
     do &var( param1, param2 )
*/

   Массивы мест позволяют оперировать своими элементами так же, как и обычными местами:

   lockf(  var[ 3 , 4 ] ,  READ_ONLY )

что не позволит использовать данный элемент по записи. К статичным массивам относятся блоки всех типов (о них подробнее в описании определителей блоков).
   Над всяким массивом может быть определен набор регионов - фрагментов массива с собственной относительной адресацией элементов.

   Region( <указание массива>, <коорд. начала1>, <коорд. конца1>
           [{,<коорд. начала2>, <коорд. конца2>}]
         )
 
   К функциям обслуживания массивов относится

ArrSize( <массив> ), которая возвращает количество байтов в массиве <массив>.

   arrVar := array( 'I' , 0 , 100 )
    . . .
   count := ArrSize( arrVar ) ;* count == 400

ElemAsStr() - возвращает указатель на элемент любого массива как на элемент строки.

   arrVar := array( 'H' , 0 , 100, 20 )
    . . .
//  элементам массива присваиваются коды знаков:
//                    H e                     l l                     o!
    arrVar[20,3] := 0x4865, arrVar[20,4] := 0x6C6C, arrVar[20,5] := 0x6F21
    arrVar[20,6] := 0
    strPtr := ElemAsStr( arrVar[20, 3] )

//  Будет веведенно: Hello!

   
outText( 20, 20, strPtr )

<<< BACK NEXT >>>