[an error occurred while processing this directive]
HP OpenVMS Systems Documentation |
HP Pascal for OpenVMS
|
Previous | Contents | Index |
Record constructors are lists of values that you can use to initialize a record; they have the following form:
[[data-type]] [ [[{{component},... : component-value};... ]] [[ CASE [[tag-identifier :]] tag-value OF [{{component},... : component-value};...] ]] [[ OTHERWISE ZERO [[;]] ]] |
You can use either of the following constructors to assign values to the record variable: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
Specifies a field in the fixed-part of the record. Fields in the constructor do not have to appear in the same order as they do in the type definition. If you choose, you can specify fields from the variant-part as long as the fields do not overlap.component-value
Specifies a value of the same data type as the component. The value is a compile-time value; if you use the constructor in the executable section, you can also use run-time values.CASE
Provides a constructor for the variant portion of a record. If the record contains a variant, its constructor must be the last component in the constructor list.tag-identifier
Specifies the tag-identifier of the variant portion of the record. This is only required if the variant part contained a tag-identifier.tag-value
Determines which component list is applicable according to the variant portion of the record.OTHERWISE ZERO
Sets all remaining components to their binary zero value. If you use OTHERWISE ZERO, it must be the the last component in the constructor.
VAR Player1 : Player_Rec VALUE [Wins: 18; Losses: 3; Percentage: 21/18]; {In executable section, constructor type is required and run-time expressions are legal:} Player1 := Player_Rec[Wins: 18; Losses: y; Percentage: y+18/18]; |
When you specify constructors for records that nest records, specify the type of the outermost record, but do not specify the type of the constructors for any nested records. Consider the following example.
TYPE Team_Rec = RECORD Total_Wins : INTEGER; Total_Losses : INTEGER; Total_Percentage : REAL; Player1 : Player_Rec; Player2 : Player_Rec; Player3 : Player_Rec; END; VAR Team : Team_Rec; {In the executable section: } Team := Team_Rec[Total_Wins: 18; Total_Losses: 3; Total_Percentage: 21/18; Player1: [Wins: 6; Losses: 0; Percentage: 1.0 ]; Player2: [Wins: 5; Losses: 2; Percentage: 7/5 ]; Player3: [Wins: 7; Losses: 1; Percentage: 8/7 ]]; |
You can call the ZERO function within record constructors to initialize all nonspecified components to their binary zero values, which are determined by the data type of each component.
Consider the following examples:
VAR Team : Team_Rec VALUE ZERO ; Team : Team_Rec VALUE [Total_Wins: 5; Total_Losses: 2; Total_Percentage: 7/5; Player2: [Wins: 5; Losses: 2; Percentage: 7/5 ]; OTHERWISE ZERO ]; {Initializes Player1 and Player3} |
To create a constructor for a record that contains a variant, use the reserved word CASE, followed by one of the following:
To complete the constructor, use the reserved word OF followed by component-list values contained in a nested constructor. Consider the following valid constructors.
TYPE Orders = RECORD Part : 1..9999; CASE On_Order : BOOLEAN OF TRUE : ( Order_Quantity : INTEGER; Price : REAL ); FALSE : ( Rec_Quantity : INTEGER; Cost : REAL ); END; VAR An_Order : Orders VALUE [Part: 2358; CASE On_Order : FALSE OF [Rec_Quantity: 10; Cost: 293.99]]; {In the executable section, constructor type is required:} An_Order := Orders [Part: 2358; CASE On_Order : FALSE OF [Rec_Quantity: 10; Cost: 293.99]]; |
Note that if you use a constructor in the type definition, you can specify an initial state for only one variant in the type. To specify an initial state for more than one variant, you must put initial state specifiers on the fields themselves. For example:
TYPE Orders = RECORD Part : 1..9999 VALUE 25; CASE On_Order : BOOLEAN OF TRUE : ( Order_Quantity : INTEGER VALUE 18; Price : REAL VALUE 4.65 ); FALSE : ( Rec_Quantity : INTEGER VALUE 10; Cost : REAL VALUE 46.50 ); END; |
A set is a collection of data items of the same ordinal type (called the base type). The SET type definition specifies the values that can be elements of a variable of that type. The SET type has the following form:
[[PACKED]] SET OF [[attribute-list]] |
One or more identifiers that provide additional information about the
base-type.
attribute-list
For sets of other ordinal base types, elements can include the full range of the type.
The INTSET predefined type is equivalent to:
TYPE INTSET = SET OF 0 .. 255; |
Set constructors are lists of values that you can use to initialize a set; they have the following form:
[[data-type]] [ [[{component-value},... ]] ] |
data-type
The data type of the constructor. This identifier is optional when used in the CONST and executable sections; do not use this identifier in the TYPE and VAR sections or in nested constructors.component-value
Specifies values within the range of the defined data type. Component values can be subranges (..) to indicate consecutive values that appear in the set definition. These values are compile-time values; if you use the constructor in the executable section, you can also use run-time values.
A set having no elements is called an empty set and is written as empty brackets ([]).
A possible constructor for a variable of type SET OF 35..115 is the following:
VAR Numbers : SET OF 35..115 VALUE [39, 67, 110..115]; {In the executable section, run-time expressions are legal:} Numbers := [39, 67, x+95, 110..115]; |
The set constructors contain up to nine values: 39, 67, x+95 (in the executable section only), and all the integers between 110 and 115, inclusive. If the expression x+95 evaluates to an integer outside of the range 35..115, then Pascal includes no set element for that expression.
To initialize a set to the empty set, do the following:
VAR Day : SET OF 1..31 VALUE []; |
A file is a sequence of components of the same type. The number of components is not fixed; a file can be of any length. The FILE type definition identifies the component type and has the following form:
[[PACKED]] FILE OF [[attribute-list]] component-type |
One or more identifiers that provide additional information about the
file components.
attribute-list
The arithmetic, relational, Boolean, and assignment operators cannot be used with file variables or structures containing file components. You cannot form constructors of file types.
When you declare a file variable in your program, HP Pascal automatically creates a file buffer variable of the component type. This variable takes on the value of one file component at a time.
To reference the file buffer variable, write the name of the associated file variable, followed by a circumflex (^). No operations can be performed on the file while a reference to the file buffer variable exists.
The following example shows two ways to declare files:
VAR True_False_File : FILE OF BOOLEAN; {File of TRUE and FALSE values} Experiment_Records : FILE OF RECORD {File of records} Trial : INTEGER; {To access, Experiment_Records^.Trial} Temp, Pressure : INTEGER; Yield, Purity : REAL; END; |
The TEXT predefined type is a file containing sequences of characters with special markers (end-of-line and end-of-file) added to the file. Although each character of a TEXT file is one file component, the end-of-line marker allows you to process the file line by line, if you choose. The TEXT type has the following form:
[[attribute-list]] |
One or more identifiers that provide additional information about the
file components.
attribute-list
As an option, you can use another format for constructors that is provided as an HP Pascal extension. HP Pascal retains this format only for compatibility with programs written for use with previous versions of this product. Also, you cannot use nonstandard constructors for variables of nonstatic types.
For all nonstandard constructors, you place constant values, of the same type as the corresponding component, in a comma list within parentheses. The compiler matches the values with the components using positional syntax; you must provide a value for each component in the variable. Nested structured components are designated by another comma list inside of another set of parentheses. Nonstandard constructors are legal in the VAR and VALUE initialization sections, and in the executable section. Specifying a type identifier as part of a constructor is optional for constructors used in the VAR and VALUE initialization sections, are required for constructors in the executable section, and cannot be used for nested constructors.
The format for nonstandard array constructors is as follows:
[[data-type]] ( [[{component-value},... ]] [[ REPEAT component-value ]] ) |
Specifies the constructor's data type. If you use the constructor in
the executable section, a data-type identifier is required. Do not use
a type identifier in the VAR or VALUE sections or for a nested
constructor.
data-type
component-value
Specifies the compile-time value to be assigned to the corresponding
array element. The compiler assigns the first value to the first
element, the second value to the second element, and so forth. If you
want to assign more than one value to more than one consecutive
element, you can use the following syntax for a component-value:
n OF value |
For example, the following component value assigns the value of 15 to the first three components of an array:
VAR Array1 : ARRAY[1..4] OF INTEGER; VALUE Array1 := ( 3 OF 15, 78 ); |
You cannot use the OF reserved word in a REPEAT clause.
An example of an array constructor is as follows:
TYPE Count = ARRAY[1..10] OF INTEGER; VAR Numbers : Count; VALUE Count := ( 3 OF 1, 2, 1, 2, 3 OF 3, 3 ); {In the executable section, constructor type is required:} Numbers := Count( 3 OF 1, 2, 1, 2, REPEAT 3 ); |
An example of a constructor for a multidimensional array is as follows:
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( (3 OF ' '), (' ', 'X', ' '), (3 OF ' ') ); |
On standard array constructors ( Section 2.4.1.2)
The format for a nonstandard record constructor is as follows:
2.4.6.2 Nonstandard Record Constructors
[[data-type]] ( [[{component-value},... ]] [[ tag-value, {component-value};... ]] ) |
An example of a record constructor is as follows:
Specifies the constructor's data type. If you use the constructor in
the executable section, a data-type identifier is required. Do not use
a type identifier in the VAR or VALUE sections or for a nested
constructor.
data-type
component-value
Specifies a compile-time value of the same data type as the component.
The compiler assigns the first value to the first record component, the
second value to the second record component, and so forth.
tag-value
Specifies a value for the tag-identifier of a variant record component.
The value that you specify as this component of the constructor
determines the types and positions of the remaining component values
(according to the variant portion of the type definition).
TYPE Player_Rec = RECORD Wins : INTEGER; Losses : INTEGER; Percentage : REAL; VAR Player1 : Player_Rec := ( 18, 6, 24/18 ); {In the executable section, constructor type is required:} Player1 := Player_Rec( 18, 6, 24/18 ); |
The following is an example of a nested record constructor:
TYPE Team_Rec = RECORD Total_Wins : INTEGER; Total_Losses : INTEGER; Total_Percentage : REAL; Player1 : Player_Rec; Player2 : Player_Rec; Player3 : Player_Rec; END; VAR Team : Team_Rec; {In the executable section: } Team := Team_Rec ( 18, 3, 18/21, ( 6, 0, 1.0 ), ( 5, 2, 5/7 ), ( 7, 1, 7/8 ) ); |
The following is an example of a variant record constructor:
TYPE Orders = RECORD Part : 1..9999; CASE On_Order : BOOLEAN OF TRUE : ( Order_Quantity : INTEGER; Price : REAL ); FALSE : ( Rec_Quantity : INTEGER; Cost : REAL ); END; VAR An_order : Orders := ( 2358, FALSE, 10, 293.99 ); |
A schema type is a user-defined construct that provides a template for a family of distinct data types. A schema type definition contains one or more formal discriminants that take the place of specific boundary values or variant-record selectors. By specifying boundary or selector values to a schema type, you form a valid data type; the provided boundary or selector values are called actual discriminants. Schema types have the following form:
schema-identifier ({{discriminant-identifier},... : [[attribute-list]] ordinal-type-name};... ) = [[attribute-list]] type-denoter; |
schema-identifier
The name of the schema.discriminant-identifier
The name of a formal discriminant.attribute-list
One or more identifiers that provide additional information about the type-denoter.ordinal-type-name
The type of the formal discriminant, which must be an ordinal type (except those types that have INTEGER64 or UNSIGNED64 base types).type-denoter
The type definition of the components of the schema. This must define a new record, array, set, or subrange type.
Each schema type definition requires at least one discriminant identifier. A discriminant identifier does not have to be used in the type-denoter definition, but Pascal still uses the discriminant identifier to determine type compatibility. Discriminant-identifiers can appear anywhere a value is required in this definition. Consider the following example:
TYPE Array_Template( Upper_Bound : INTEGER ) = ARRAY[1..Upper_Bound] OF INTEGER; |
The identifier Upper_Bound is the formal discriminant of the Array_Template schema. The Array_Template schema is not a complete description of data. It is not a valid data type until you provide an actual discriminant that designates the upper boundary of the array template. Schema types that have not been provided actual discriminants are called undiscriminated schema; in the previous example, Array_Template is an undiscriminated schema. You can use an undiscriminated schema in the following instances:
In an undiscriminated schema declaration, you can use a combination of formal discriminants, compile-time values, and nested discriminants to form subrange bounds. These types of expressions are called nonvarying expressions. Consider the following:
TYPE Vector( d : INTEGER ) = ARRAY[0..d-1] OF BOOLEAN; Number_Line( Starting, Distance : INTEGER ) = Starting..Starting+Distance; My_Subrange( l,u : INTEGER ) = l..u; Shift_Array_Index( l2, u2, Length : INTEGER ) = ARRAY[My_Subrange( l2+10, u2+10 )] OF STRING( Length ); |
The following example provides the Array_Template schema with actual discriminants to form complete data types (the remaining examples in this section use the Array_Template declaration).
TYPE Array_Template( Upper_Bound : INTEGER ) = ARRAY[1..Upper_Bound] OF INTEGER; VAR Array1 : Array_Template( 10 ); {ARRAY[1..10] OF INTEGER;} Array2 : Array_Template( x ); {Upper boundary determined at run time by variable or function call} |
In the previous example, the actual discriminants 10 and x complete the boundaries for Array_Template, forming two complete data types within the same schema type family. A schema type that has been provided actual discriminants is called a discriminated schema; discriminated schema can appear in either the TYPE or VAR sections. The type specifiers Array_Template( 10 ) and Array_Template( x ) are examples of discriminated schema.
Actual discriminants can be compile- or run-time expressions. This expression must be assignment compatible with the ordinal type specified for the formal discriminant. Also, the actual discriminant value must be inside the range specified for the formal discriminant; in the case of subranges, the upper value must be greater than or equal to the lower value. In the previous example, 10 and x must be within the range -MAXINT..MAXINT.
If you want to use a discriminated schema type as the domain type of a pointer or as the type of a formal parameter, give the discriminated schema type a name by declaring it in the TYPE section. Consider the following:
TYPE Array_Type1 = Array_Template( 10 ); PROCEDURE Example( Param : Array_Type1 ); {Procedure body...} |
For any undiscriminated schema, there is a range of possible data types that you can form by discrimination. A schema family is the undiscriminated schema type and the range of data types that can be formed from it. Also, two separate discriminations that provide the same actual discriminant value specify the same data type. Consider the following.
TYPE My_Subrange( a, b : INTEGER ) = a..b; Sub_A = My_Subrange( 1, 5 ); Sub_B = My_Subrange( 1, 5 ); Sub_C = My_Subrange( -50, 50 ); |
The types Sub_A, Sub_B, and Sub_C are all of the My_Subrange schema-type family. Sub_A and Sub_B are of the same data type. Consider the following.
TYPE My_Subrange( a, b : INTEGER ) = a..b; My_Array( Upper : INTEGER ) = ARRAY[1..Upper] OF INTEGER; VAR i : My_Array( 10 ); j : My_Array( 10 ); k : My_Array( 15 ); l : ARRAY[ My_Subrange( 1, 10 ) ] OF INTEGER; m : ARRAY[ My_Subrange( 1, 10 ) ] OF INTEGER; {In the executable section:} i := j; {Legal; same schema family, same actual discriminant} i := k; {Illegal; same schema family, different actual} i := l; {Illegal; different types} l := m; {Illegal; different types} |
Types l and m are not assignment compatible despite having the same subrange values specified by the same schema type; the two distinct type declarations create two distinct types, regardless of the ranges of the two types.
Once you create a discriminated schema, you can access the value of an actual discriminant. Consider the following example:
VAR Array1 : Array_Template( 10 ); {In the executable section:} WRITELN( Array1.Upper_Bound ); {Writes 10 to the default device} |
Discriminant values can appear in all expressions except constant expressions. The following example shows a valid use of the discriminant-value expression:
FOR i := 1 TO Array1.Upper_Bound DO Array1[i] := i; |
You can use discriminated schema in the type-denoter of a schema definition. You can also discriminate a schema in the type-denoter of a schema definition, but the actual discriminants must be expressions whose values are nonvarying; the actual discriminants cannot be variables or function calls.
Consider the following valid schema definitions:
Previous | Next | Contents | Index |