[an error occurred while processing this directive]
HP OpenVMS Systems Documentation |
HP Pascal for OpenVMS
|
Previous | Contents | Index |
For More Information:
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 |
One or more identifiers that provide additional information about the
base type.
attribute-list
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.
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:
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.
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 |
One or more identifiers that provide additional information about the component type.attribute-list
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'; |
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']]; |
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; |
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:
TYPE Orders = RECORD Part : 1..9999; CASE On_Order : BOOLEAN OF TRUE : ( Order_Quantity : INTEGER; Price : REAL ); FALSE : ( Rec_Quantity : INTEGER; Cost : REAL ); END; |
TYPE Characters = RECORD CASE CHAR OF 'A'..'Z' : ( Capital : INTEGER ); '0'..'9' : ( Number : INTEGER ); OTHERWISE ( Misc : BOOLEAN ); END; |
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.
Previous | Next | Contents | Index |