ugBASIC User Manual

Arrays

It is often necessary to use a whole set of similar variables for something like a table of soccer results or a catalogue for a record collection. Any set of variables can be grouped together in an “array”.

Defining an array

Supposing you have 100 titles in your record collection, and you need to size the set of variables needed for your array. There is a special command for setting up this dimension.

The DIM command is used to dimension an array, and the variables in your record collection table could be set up with a first line like this:

DIM artist$(100), title$(100), year(100), price(100)

So, artist$, title, and so on, are the names of the arrays, while 100 is the size.

Each dimension in the table is held inside round brackets, and if there is more than one element in a dimension each number must be separated from the next by a comma.

DIM chessboard(8,8)

This command will define a two-dimensional array, i.e. a matrix. Element numbers in arrays always start from zero, so the first entry must be indexed using 0, while the last entry can be accessed using the size minus one:

artist$(0)="Cindy Lauper"
title$(0)="Girls Just Want To Have Fun"
year(0)=1983
price(0)=10
artist$(99)="David Bowie"
title$(99)="Space Oddity"
year(99)=1967
price(99)=8


To extract elements from any array, you could then add something like this to your example program:

PRINT title$(0): PRINT price(0)
PRINT title$(99): PRINT year(99): PRINT price(99)


Bounds

These tables can have up to 256 dimensions as you like, and each dimension can have up to 65.535 elements. The size of the array is actually limited by the available memory, which is different depending on the retrocomputer used.

Here are some examples:

DIM list(5), number(5,4,3), word$(5,5)

Once you define an array, you cannot change its size dynamically at runtime. However, it is possible to programmatically know what is the maximum value of the index is by using the UBOUND statement. The syntax for the given arrays follows:

PRINT UBOUND(number) : REM 5

If the array has more than one dimension, you can get the size of a specific dimension by putting it after the array's name:

PRINT UBOUND(number,0) : REM it is like UBOUND(number)
PRINT UBOUND(number,2) : REM is 3

There is also an instruction to know the minimum value of the index (LBOUND), but this value will always be 0.

Type an array

It is possible to define the "type" of the elements of an array, which must be the same for all elements. The ugBASIC language allows you to define the type in three ways: implicitly, explicitly, and in full.

The implicit way occurs by calling the DIM instruction without indicating any type: in this case, ugBASIC will use the default type which is INT (signed 16-bit value).

DIM integers(42)

You can change the default type with the DEFINE DEFAULT TYPE statement, and this change will be reflected in the next DIM statement.

DIM integers(42)
DEFINE DEFAULT TYPE LONG
DIM longs(42)

The explicit way is to use, at the end of the array name, a symbol that indicates the type: the dollar sign ($) for strings, the percentage symbol (%) for integers, and so on. Note that once the type is defined in this way, it is not necessary to use the symbol to refer to the array, as the type is understood to be defined by the DIM, and cannot be changed at runtime.

DIM strings$(42)
DIM integers%(42)
integers(10)=21 : ' type is implicitly INT
strings(10)="test" : ' type is implicitly STRING

The complete way is to use the AS keyword, which allows you to specify the type of each element precisely and punctually.

DIM strings(42) AS STRING
DIM integers(42) AS INT

Initialize array

When you define an array, it is filled with zeros (if it is numeric) or empty strings (if it is string). It is possible, for numeric arrays, to fill it with different values, so that it assumes them when the program starts. There are various ways to initialize arrays.

The simplest way is to directly indicate the constant to use, with the WITH keyword. In this case, this value will be assigned to all elements of the arrays. Example:

DIM integers(4) WITH 42
PRINT integers(1) : ' will print "42"

Another way is to indicate, explicitly and individually, the elements of the array. In this language arrays are organized first by rows and then by columns.



In practice, first the elements with the rightmost dimensional index are stored consecutively, then gradually towards the left, until the last element.

DIM integers(3,2) = #{ 10, 20, 30, 40, 50, 60 }
PRINT integers(1,0) : ' will print "30"

An alternative way is to define byte by byte the memory area that will be occupied by the array: in this case, it is necessary for the programmer to know how the ugBASIC array is organized. In this language, arrays are contiguous memory areas, where the elements are organized exactly as they are from a logical point of view. Therefore, assuming that the default type is INT and wanting to fill it statically at the beginning of the program, it is sufficient to insert the 60 bytes, two bytes for each element. The syntax for initializing an array in this way is the sequence #[...], where the last parenthesis is optional, and each byte must be defined with two hexadecimal digits. For example:

DIM integers(3,2) = #[0010002000030004000500060]
PRINT integers(1,0) : ' will print "48" ("30" is hexadecimal!)

Note that this way of initializing an array is not isomorphic, in the sense that it must adapt to each type of processor. In particular, if you need to initialize values larger than one byte, it is important to consider their order within the processor. In this regard, there are two constants, LITTLE ENDIAN and BIG ENDIAN which allow us to know the order in which they must be defined.

Finally, it is possible to load a text file (in a sort of "CSV" type format) with the LOAD ... AS TEXT instruction.

DIM integers(4) = LOAD "numbers.txt" AS TEXT

When initializing a vector (i.e. an array with a dimension), you can omit the dimension, because ugBASIC will automatically calculate it based on the data used to initialize it.

DIM integers() = #[0010002000300040]

Note that retrocomputers may have little RAM available to store data, and arrays may never need to change during code execution. This is especially true for arrays used as "game maps". In that case, you can tell ugBASIC that the array will be "read-only", and therefore that it shouldn't take up any space. This is possible with the use of the READ ONLY (or READONLY) keyword.

DIM gamemap() = #[10203040] READ ONLY

Filling an array

For arrays that are not "read-only", you can modify them during program execution, either punctually or massively. The simplest way is to use the ARRAY command to reinitialize the array, exactly as was done with the DIM command.

DIM integers(3,2) = #{ 10, 20, 30, 40, 50, 60 }
PRINT integers(1,0) : ' will print "30"
ARRAY integers = #{ 53, 21, 10, 00, 00, 00 }
PRINT integers(1,0) : ' will print "10"

Clearly, if you have two variables of the same type and size, you can copy one on the other.

DIM integers1(3,2)
DIM integers2(3,2)
integers2 = integers1

Alternatively, if you want to fill an array with the same value, for example to reset it to zero, you can use the FILL command.

DIM integers(3,2) = #{ 10, 20, 30, 40, 50, 60 }
PRINT integers(1,0) : ' will print "30"
FILL integers
PRINT integers(1,0) : ' will print "0"
FILL integers WITH 42
PRINT integers(1,0) : ' will print "42"