[an error occurred while processing this directive]

HP OpenVMS Systems Documentation

Content starts here

HP Pascal for OpenVMS
Language Reference Manual


Previous Contents Index

For More Information:

  • On operators ( Section 4.2)
  • On the internal representation of real numbers ( Section A.3.2)
  • On compilation switches (HP Pascal for OpenVMS User Manual)

2.3 Pointer Types

A pointer type allows you to refer to a dynamic variable. Dynamic variables do not have lifetimes that are strictly related to the scope of a routine, module, or program; you can create and eliminate them at various times during program execution. Also, pointer types clearly define the type of an object, but you can create or eliminate objects during program execution.

The syntax of a pointer type is as follows:


[[attribute-list]] ^ [[attribute-list]] base-type-identifier

attribute-list

One or more identifiers that provide additional information about the base type.

base-type-identifier

The type identifier of the dynamic variable to which the pointer refers. The base type can be any type name or schema name. (If the base type is an undiscriminated schema type, you need to supply actual discriminants when you call the NEW function.)

Unlike other variables, dynamic variables do not have identifiers. You can access them indirectly with pointers.

When you use pointers, you call the procedure NEW to allocate storage for dynamic variables. You call the procedure DISPOSE to deallocate this storage.

A variable of a pointer type refers to a dynamic variable of the base type and is said to be associated with that type. In the following example, the variable Ptr is associated with a record of type My_Rec:


TYPE
   My_Rec = RECORD
      Name : STRING( 30 );
      Age  : INTEGER;
   END VALUE [Name: 'Chris Lee'; Age: 29]; {Initialized}
VAR
   Ptr : ^My_Rec;

{In executable section:}
NEW( Ptr );

To reference the dynamic variable to which a pointer refers, write the pointer variable name followed by a circumflex (^). The following example assigns values to the record variable Ptr^:


Ptr^ := My_Rec[Name: 'Kim Jones'; age: 65];

Pointers assume values through initialization, assignment, and the READ and NEW procedures. The value of a pointer is either the storage address of a dynamic variable or the predeclared identifier NIL. NIL indicates that the pointer does not currently refer to a dynamic variable.

A file referenced by a pointer is not closed until the execution of the program terminates or until the dynamic variable is deallocated with the DISPOSE procedure. If you do not want the file to remain open throughout program execution, you must use the CLOSE procedure to close it.

The following example declares the pointer variable Ptr as a pointer to an integer and initializes Ptr to NIL:


VAR
   Ptr : ^INTEGER VALUE NIL;

For performance reasons on OpenVMS I64 systems, the HP Pascal compiler assumes that all pointers point to objects that are aligned on at least octaword boundaries. The NEW predeclared routine always returns memory that is aligned on octaword boundaries.

For performance reasons on OpenVMS Alpha systems, the HP Pascal compiler assumes that all pointers point to objects that are aligned on at least quadword boundaries. The NEW predeclared routine always returns memory that is aligned on quadword boundaries.

For pointers holding addresses which are not quadword aligned, you can explicitly specify the expected alignment of the pointer base type. For example:


 var
    p : ^ [aligned(0)] integer; { Pointer to a byte-aligned integer }

By default, all pointer types on OpenVMS I64 and OpenVMS Alpha systems are 32 bits. You can declare a 64-bit pointer by using the [QUAD] attribute in a pointer declaration. For example:


  var
       long_ptr : ^integer;
       quad_ptr : [quad] ^integer;

  begin
    new(long_ptr);
    quad_ptr := long_ptr;
    quad_ptr^ := 5;
    if quad_ptr <> long_ptr then quad_ptr := long_ptr;
    end;

When comparing a 32-bit and a 64-bit pointer, the 32-bit pointer will be sign-extended before the comparison. Also, when assigning a 32-bit pointer value into a 64-bit pointer variable, the value will be sign-extended. You cannot assign a 64-bit pointer value into a 32-bit pointer variable.

For More Information:

  • On the NEW procedure ( Section 8.60)
  • On the DISPOSE procedure ( Section 8.28)
  • On records ( Section 2.4.2)
  • On pointers to schema types ( Section 2.5)
  • On linked lists (HP Pascal for OpenVMS User Manual)
  • On compiler switches for selecting alignment, packing, and allocation rules for each platform (HP Pascal for OpenVMS User Manual)

2.3.1 POINTER Type

The POINTER predefined type is compatible with all pointer types. Variables or functions of type POINTER cannot be dereferenced or used with the NEW and DISPOSE procedures. In order to access the data, you must assign the pointer value into a variable of a particular pointer type or typecast the pointer to a particular pointer type. For example, you can use the POINTER type in the following ways:

  • To assign to or from any other type of pointer, including function result variables
  • To compare equality with any other type of pointer
  • To pass actual parameters of type POINTER to VAR and value parameters of any other type of pointer
  • To accept parameters of any other type of pointer with formal parameters of type POINTER

2.4 Structured Types

The structured data types are user defined and consist of components. Each component of a structured data type has its own data type; components can be any type.

To express values of structured objects (arrays, records, and sets), you can use a list of values called constructors. Constructors are valid in the TYPE, CONST, VAR, and executable sections of your program. Examples of valid constructors are provided throughout the following sections. The following sections also contain examples that show how to assign values to individual components of structured objects.

To save storage space, you can specify PACKED before any structured type identifier except VARYING OF CHAR PACKED ARRAY, PACKED RECORD, and PACKED SET). Defining PACKED structured types causes the compiler to economize storage by storing the structure in as few bits as possible. Keep in mind, however, that a packed data item is not compatible with a data item that is not packed. Also, accessing components of some packed structures can be slower than accessing components of unpacked structures.

HP Pascal also provides the predefined structured type TIMESTAMP for more easily manipulating date and time information.

For More Information:

2.4.1 ARRAY Types

An array is a group of components (called elements) that all have the same data type and share a common identifier. An individual element of an array is referred to by an ordinal index (or subscript) that designates the element's position (or order) in the array.

An array type has the following form:


[[PACKED]] ARRAY [{[[attribute-list]] index-type},...] OF [[attribute-list]] component-type

attribute-list

One or more identifiers that provide additional information about the component type.

index-type

The type of the index, which can be any ordinal type or discriminated ordinal schema type.

component-type

The type of the array components, which can be any type. The components of an array can be another array.

The indexes of an array must be of an ordinal type. However, specifying large types, such as INTEGER, as the index type can cause the memory request to exceed available memory space. To use integer values as indexes, you must specify an integer subrange in the data type definition (unless you are using a conformant-array parameter).

You can use an array component anywhere in a program that a variable of the component type is allowed. Also, the only operation defined for entire array objects is the assignment operation (:=) (unless your array components are of a FILE type).

2.4.1.1 ARRAY Components

To refer to an array component, you specify the name of the array variable (or the name of an object whose result, when used as an expression, is of an array type), followed by an index value enclosed in brackets ([]). Consider the following:


TYPE
   Count = ARRAY[1..10] OF INTEGER;  {Array type of 10 integers}
VAR
   Numbers : Count;                  {Array variable}
{In the executable section:}
Numbers[5] := 18;  {Assigns the value 18 to the fifth element}

HP Pascal also allows array components to be arrays. These types of arrays are called multidimensional arrays. The following example shows two ways of declaring the same multidimensional array:


VAR
   Tic_Tac_Toe : ARRAY[1..3] OF ARRAY['a'..'c'] OF CHAR;
      {Or equivalently:}
   Tic_Tac_Toe : ARRAY[1..3, 'a'..'c'] OF CHAR; {3x3 matrix}

{In the executable section:}
Tic_Tac_Toe[ 1, 'a' ] := 'X';  {Or equivalently:}
Tic_Tac_Toe[1]['a']   := 'X';

For More Information:

2.4.1.2 ARRAY Constructors

Array constructors are lists of values that you can use to specify an array value; they have the following form:


                              {component           }
         [[data-type]] [ [[{{ {component-subrange  } },... : component-value};... ]]
            [[OTHERWISE component-value [[;]] ]] ]

data-type

Specifies the constructor's data type. If you use the constructor in the executable section or in the CONST section, a data-type identifier is required. Do not use a type identifier in initial-state specifiers elsewhere in the declaration section or in nested constructors.

component

component-subrange

Specifies an element number to which the component-value applies. You can specify a subrange of components. Array elements do not have to be specified in order. The component must be a compile-time value or constant.

component-value

Specifies the value to be assigned to the array elements in the component list; the value must be of the same data type as the array-component type. This value is a compile-time value; if you use the constructor in the executable section, you can also use a run-time value.

OTHERWISE

Specifies a value to be assigned to all array elements that have not already been assigned values.

When using array constructors, you must initialize all elements of the array; you cannot partially initialize the array.

For example, you can use either of these constructors to assign values to the array variable:


VAR
   Numbers : Count VALUE [1..3,5 : 1;  4,6 : 2;  7..9 : 3;  10 : 6];
{In the executable section, constructor type is required:}
Numbers := Count[1..3,5 : 1;  4,6 : 2;  7..9 : 3;  10 : x+3];

These constructors give the first, second, third, and fifth component the value 1; the fourth and sixth component the value 2; and the seventh, eighth, and ninth components the value 3. The first constructor gives the tenth component the value 6; the second constructor, since it is in the executable section, can assign the run-time value x+3 to the tenth component.

To specify values for all remaining elements, you can use the OTHERWISE clause, as follows:


Numbers := Count[4,6 : 2;  7..9 : 3;  10 : x+3; OTHERWISE 1];

When you specify constructors for multidimensional arrays in the executable section, only specify the type of the outermost array. Consider the following example:


TYPE
   One_Dimension = ARRAY[1..3] OF CHAR;
   Matrix = ARRAY['a'..'b'] OF One_Dimension;
VAR
   Tic_Tac_Toe : Matrix;
{In the executable section:}
Tic_Tac_Toe := Matrix[ 1,3 : [OTHERWISE ' '];
                       2 : [ 1,3 : ' '; 2 : 'X']];

For More Information:

2.4.2 RECORD Types

A record is a group of components (called fields) that can be of various data types. Each record component can contain one or more data items, including embedded records. The record type has the following from:


[[PACKED]] RECORD [[field-list]] END

If field-list is not specified, an empty record is created. The syntax of field-list is as follows:


         {{{field-identifier},... : [[attribute-list]] type};... [[; variant-clause]] [[;]]  }
         {variant-clause [[;]]                                                               }

field-identifier

The name of a field.

attribute-list

One or more identifiers that provide additional information about the field.

type

The type of the corresponding field. A field can be of any type.

variant-clause

The variant part of the record.

The names of the fields must be unique within one record type, but can be repeated in different record types. You can specify the fields by specifying the record variable name (or the name of an object whose result, when used as an expression, is of a record type), followed by a period (.), and followed by the field name. If the record is unpacked, you can use a field anywhere in a program that a variable of the field type is allowed. (This manual flags circumstances in which components of packed records cannot appear where a variable of the field type is allowed.) The only operation defined for entire records is the assignment operation (:=).

The following example shows how to assign a value to a record component:


TYPE
   Player_Rec = RECORD
      Wins       : INTEGER;
      Losses     : INTEGER;
      Percentage : REAL;
      END;
VAR
   Player1, Player2 : Player_Rec;
{In the executable section:}
Player1.Wins := 18;  {Assigns the value 18 to the Wins field.}

You can partially initialize a record using the VALUE predeclared identifier on individual fields, as follows:


VAR
   Player : RECORD
      Wins       : INTEGER VALUE 18; {Initial value for one field}
      Losses     : INTEGER;
      Percentage : REAL;
      END;

A record type can include fields that are themselves records. In this case, the name of the field includes the name of every record within which it is nested. Consider the following:


TYPE
   Team_Rec = RECORD
      Total_Wins       : INTEGER;
      Total_Losses     : INTEGER;
      Total_Percentage : REAL;
      Player1          : Player_Rec;   {Defined in previous example}
      Player2          : Player_Rec;
      Player3          : Player_Rec;
      END;
VAR
   Team : Team_Rec;

You can calculate the team's wins with the following code:


Team.Total_Wins := Team.Player1.Wins +
                   Team.Player2.Wins +
                   Team.Player3.Wins;

For More Information:

2.4.2.1 Records with Variants

A record can include one or more fields or groups of fields called variants, which can contain different types or amounts of data at different times during program execution. When you use a record with variants, two variables of the same record type can represent different data. You can define a variant clause only for the last field in the record. The syntax for record variants is as follows:


              {[[tag-identifier : ]] [[attribute-list]] tag-type-identifier  }
         CASE {discriminant-identifier                                       } OF
            {case-label-list : (field-list)};...
            [[ [[;]] OTHERWISE (field-list) ]]

tag-identifier

The name of the tag field.

attribute-list

One or more identifiers that provide additional information about the variant.

tag-type-identifier

The type identifier for the tag field.

discriminant-identifier

The name of the formal discriminant of a schema type. The value of the corresponding actual discriminant selects the active variant. Once you select the variant by discrimination, you cannot change it again. Consider the following:


TYPE
   Record_Template( a : INTEGER ) = RECORD
      Field_1 : REAL;
      CASE a OF
         0 : ( x : INTEGER );
         1 : ( y : REAL );
      END;

case-label-list

One or more case constant values of the tag field type separated by commas. A case constant is either a single constant value (for example, 1) or a range of values (for example, 5..10). You must enumerate one label for each possible value in the tag-type-identifier.

field-list

The names, types, and attributes of one or more fields. At the end of a field list, you can specify another variant clause. The field list can be empty.

The tag field consists of the elements between the reserved words CASE and OF. The tag field is common to all variants in the record type. The tag field data type corresponds to the case label values and determines the current variant.

As the syntax description shows, the tag field can be a discriminant-identifier or can be specified in one of the following ways:

  • tag-identifier : [[attribute-list]]
    The tag-identifier and tag-type-identifier define the name and type of the tag field. The tag-type-identifier must denote an ordinal type. You refer to the tag field in the same way that you refer to any other field in the record (with the record.field-identifier syntax).
    The following example shows the use of the tag-identifier form:


    TYPE
       Orders = RECORD
       Part : 1..9999;
       CASE On_Order : BOOLEAN OF
          TRUE  : ( Order_Quantity : INTEGER;
                    Price          : REAL );
          FALSE : ( Rec_Quantity   : INTEGER;
                    Cost           : REAL );
       END;
    

    In this example, the last two fields in the record vary depending on whether the part is on order. Records for which the value of the tag-identifier On_Order is TRUE will contain information about the current order; those for which it is FALSE, about the previous shipment.
  • [[attribute-list]]
    In the second form, there is no tag-identifier you can evaluate to determine the current variant. If you use this form, you must keep track of the current variant yourself. The tag-type-identifier must denote an ordinal type.
    The following example shows the specification of a tag field without a tag-identifier:


    TYPE
       Characters = RECORD
       CASE CHAR OF
           'A'..'Z'  : ( Capital : INTEGER );
           '0'..'9'  : ( Number  : INTEGER );
           OTHERWISE   ( Misc    : BOOLEAN );
       END;
    

    In this example, the last field in this record will be one of the following:
    • The integer field Capital if the range 'A'..'Z' is the variant most recently referred to
    • The integer field Number if the range '0'..'9' is the variant most recently referred to
    • The Boolean field Misc if the character value falls outside the previous two variants

You can refer only to the fields in the current variant. You should not change the variant while a reference exists to any field in the current variant.

You can include an OTHERWISE clause as the last case label list. OTHERWISE is equivalent to a case label list that contains tag values (if any) not previously used in the record. The variant labeled with OTHERWISE is the current variant when the tag-identifier has a value that does not occur in any of the case label lists.

The variant can contain a nested variant, as follows:


VAR
   Hospital : RECORD
   Patient   : Name;
   Birthdate : Date;
   Age       : INTEGER;
   CASE Pat_Sex : Sex OF
        Male   : ();
        Female : ( CASE Births : BOOLEAN OF
                       FALSE  : ();
                       TRUE   : ( Num_Kids : INTEGER ));
   END;

This record includes a variant field for each woman based on whether she has children. A second variant, which contains the number of children, is defined for women who have children.

For More Information:


Previous Next Contents Index