4.32 ArraysRecords as Record Fields


4.32 Arrays/Records as Record Fields

Records may contain other records or arrays as fields. Consider the following definition:

 type      Pixel:           record                Pt:      point;                color:   dword;           endrecord; 

The definition above defines a single point with a 32-bit color component. When initializing an object of type Pixel, the first initializer corresponds to the Pt field, not the x-coordinate field. The following definition is incorrect:

 static      ThisPt: Pixel := Pixel:[ 5, 10 ]; // Syntactically incorrect! 

The value of the first field ("5") is not an object of type point. Therefore, the assembler generates an error when encountering this statement. HLA will allow you to initialize the fields of Pixel using declarations like the following:

 static      ThisPt: Pixel := Pixel:[ point:[ 1, 2, 3 ], 10 ];      ThatPt: Pixel := Pixel:[ point:[ 0, 0, 0 ], 5 ]; 

Accessing Pixel fields is very easy. Like a high level language you use a single period to reference the Pt field and a second period to access the x, y, and z fields of point:

      stdout.put( "ThisPt.Pt.x = ", ThisPt.Pt.x, nl );      stdout.put( "ThisPt.Pt.y = ", ThisPt.Pt.y, nl );      stdout.put( "ThisPt.Pt.z = ", ThisPt.Pt.z, nl );           .           .           .      mov( eax, ThisPt.Color ); 

You can also declare arrays as record fields. The following record creates a data type capable of representing an object with eight points (e.g., a cube):

 type      Object8:           record                Pts:      point[8];                Color:    dword;           endrecord; 

This record allocates storage for eight different points. Accessing an element of the Pts array requires that you know the size of an object of type point(remember, you must multiply the index into the array by the size of one element, 12 in this particular case). Suppose, for example, that you have a variable CUBE of type Object8. You could access elements of the Pts array as follows:

 // CUBE.Pts[i].x := 0;           mov( i, ebx );           intmul( 12, ebx );           mov( 0, CUBE.Pts.x[ebx] ); 

The one unfortunate aspect of all this is that you must know the size of each element of the Pts array. Fortunately, you can rewrite the code above using @size as follows:

 // CUBE.Pts[i].x := 0;           mov( i, ebx );           intmul( @size( point ), ebx );           mov( 0, CUBE.Pts.x[ebx] ); 

Note in this example that the index specification ("[ebx]") follows the whole object name even though the array is Pts, not x. Remember, the "[ebx]" specification is an indexed addressing mode, not an array index. Indexes always follow the entire name; you do not attach them to the array component as you would in a high level language like C/C++ or Pascal. This produces the correct result because addition is commutative, and the dot operator (as well as the index operator) corresponds to addition. In particular, the expression "CUBE.Pts.x[ebx]" tells HLA to compute the sum of CUBE (the base address of the object) plus the offset to the Pts field, plus the offset to the x field plus the value of EBX. Technically, we're really computing offset(CUBE)+offset(Pts)+EBX+offset(x) but we can rearrange this because addition is commutative.

You can also define two-dimensional arrays within a record. Accessing elements of such arrays is no different than any other two-dimensional array other than the fact that you must specify the array's field name as the base address for the array. For example:

 type      RecW2DArray:           record                intField: int32;                aField: int32[4,5];                     .                     .                     .           endrecord; static      recVar: RecW2DArray;           .           .           .      // Access element [i,j] of the aField field using Row-major ordering:      mov( i, ebx );      intmul( 5, ebx );      add( j, ebx );      mov( recVar.aField[ ebx*4 ], eax );           .           .           . 

The preceding code uses the standard row major calculation to index into a 4x5 array of double words. The only difference between this example and a standalone array access is the fact that the base address is recVar.aField.

There are two common ways to nest record definitions. As noted earlier in this section, you can create a record type in a type section and then use that type name as the data type of some field within a record (e.g., the Pt:point field in the Pixel data type above). It is also possible to declare a record directly within another record without creating a separate data type for that record; the following example demonstrates this:

 type      NestedRecs:           record                iField: int32;                sField: string;                rField:                     record                          i:int32;                          u:uns32;                     endrecord;                cField:char;           endrecord; 

Generally, it's a better idea to create a separate type rather than embed records directly in other records, but nesting them is perfectly legal and a reasonable thing to do on occasion.

If you have an array of records and one of the fields of that record type is an array, you must compute the indexes into the arrays independently of one another and then use the sum of these indexes as the ultimate index. The following example demonstrates how to do this:

 type      recType:           record                arrayField: dword[4,5];                << Other Fields >>           endrecord; static      aryOfRecs: recType[3,3];           .           .           .      // Access aryOfRecs[i,j].arrayField[k,l]:      intmul( 5, i, ebx );             // Computes index into aryOfRecs      add( j, ebx );                   // as (i*5 +j)*@size( recType ).      intmul( @size( recType ), ebx );      intmul( 3, k, eax );             // Computes index into arrayField      add( l, eax );                   // as (k*3 + j) (*4 handled later).      mov( aryOfRecs.arrayField[ ebx + eax*4 ], eax ); 

Note the use of the base plus scaled indexed addressing mode to simplify this operation.




The Art of Assembly Language
The Art of Assembly Language
ISBN: 1593272073
EAN: 2147483647
Year: 2005
Pages: 246
Authors: Randall Hyde

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net