[an error occurred while processing this directive]

HP OpenVMS Systems Documentation

Content starts here

HP Pascal for OpenVMS
Language Reference Manual


Previous Contents Index

2.4.2.2 Record Constructors

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 [[;]] ]]

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.
You can use either of the following constructors to assign values to the record variable:


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:

  • A tag-identifier and a colon (:), followed by a constant expression (if you use both a tag-identifier and a tag-type-identifier in the declaration)
  • A constant expression (if you use only a discriminant-identifier or a tag-type-identifier in the declaration)

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;

For More Information:

2.4.3 SET Type

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]]

attribute-list

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

base-type

The ordinal type identifier or type definition, or discriminated schema type, from which the set elements are selected. Real numbers cannot be elements of a set type.
You define a set by listing all the values that can be its elements. A set whose base type is integer or unsigned has two restrictions. First, the set can not contain more than 256 elements. Second, the ordinal value of the elements in a set must be within the range of 0 and 255.

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;

For More Information:

2.4.3.1 Set Constructors

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 [];

2.4.4 FILE Type

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

attribute-list

One or more identifiers that provide additional information about the file components.

component-type

The type of the file components. This type can be any ordinal, real, pointer, or structured type except for the following:
  • Nonstatic type
  • Structured type with a nonstatic component
  • File type
  • Structured type with a file component

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;

For More Information:

2.4.5 TEXT Type

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]]

attribute-list

One or more identifiers that provide additional information about the file components.

For More Information:

2.4.6 Nonstandard Constructors

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.

For More Information:

2.4.6.1 Nonstandard Array Constructors

The format for nonstandard array constructors is as follows:


[[data-type]] ( [[{component-value},... ]] [[ REPEAT component-value ]] )

data-type

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.

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.

REPEAT

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

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 ' ') );

For More Information:

On standard array constructors ( Section 2.4.1.2)

2.4.6.2 Nonstandard Record Constructors

The format for a nonstandard record constructor is as follows:


[[data-type]] ( [[{component-value},... ]] [[ tag-value, {component-value};... ]] )

data-type

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.

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).

An example of a record constructor is as follows:


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 );

For More Information:

2.5 Schema Types

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:

  • As the domain type of a pointer
  • As the type of a formal parameter

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