Every piece of data that is created or manipulated by a VSI Pascal program has a data type. The data type determines the range of values, set of valid operations, and maximum storage allocation for each piece of data.
1 – Ordinal
The values in an ordinal type have a one-to-one correspondence with the set of positive integers. The values are ordered so that each has a unique ordinal value indicating its position in a list of values of that type.
1.1 – INTEGER Types
VSI Pascal provides the INTEGER, INTEGER64 (not available on all systems) integer types. Also provided are the INTEGER8, INTEGER16, and INTEGER32 types, which are used as synonyms for subranges of the INTEGER type. The range of integer values consists of positive and negative integer values and of the value 0. The range boundaries depend on the architecture of the machine you are using. The largest possible value of the INTEGER type is represented by the predeclared constant MAXINT. The largest possible value of the INTEGER64 type is represented by the predeclared constant MAXINT64.
1.1.1 – Standard Int Radix
Extended digit notation allows you to express integer values in terms of a base number. VSI Pascal accepts numbers in bases 2 through 36. Syntax: [[ + | - ]] base-number#[[']]extended-digit[[']] The 'base-number' specifies the base of the number. The 'extended-digit' specifies the notation that is appropriate for the specified base. You can use extended-digit notation in the same way you use the conventional integer notation, with the following exceptions: o Extended-digit values cannot be used as labels. o Extended-digit notation for INTEGER objects cannot be used to express numbers outside the range of 0 to MAXINT. (To express signed numbers, place the unary plus operator (+) or the unary minus operator (-) in front of the notation; setting or clearing the high order bit does not set or clear the sign bit.) VSI Pascal allows the use of spaces and tabs to make the extended-digit notation easier to read. To use spaces and tabs, enclose the extended digit in single quotation marks (' '). The following are integer values in the extended-digit notation: 2#10000011 2#'1000 0011' 32#1J -16#'7FFF FFFF'
1.1.2 – Nonstandard Int Radix
VSI Pascal provides another extended integer convention for compatibility with previous versions of the language. This notation specifies an integer in either binary (base 2), octal (base 8), or hexadecimal (base 16) notation. Syntax: b [[ + | - ]] % o [[']]extended-digit[[']] x The 'b', 'o', or 'x' specifies binary, octal, or hexidecimal notation, respectively. The 'extended-digit' specifies the notation that is appropriate for the specified base. The following are extended integer values in the VSI Pascal specific notation: %b'1000 0011' %O'7712' -%x'DEC'
1.2 – INTEGER_ADDRESS
The INTEGER_ADDRESS predefined type is an integer that has the same underlying bit size as a pointer. On OpenVMS systems, INTEGER_ADDRESS is equivalent to INTEGER32.
1.3 – INTEGER8
The INTEGER8 predefined type is equivalent to the following: Syntax: TYPE INTEGER8=[BYTE]-128..127;{ 16#80..16#7F}
1.4 – INTEGER16
The INTEGER16 predefined type is equivalent to the following: Syntax: TYPE INTEGER16=[WORD]-32768..32767;{ 16#8000..16#7FFF }
1.5 – INTEGER32
The INTEGER32 predefined type is equivalent to the following: Syntax: TYPE INTEGER32=[LONG]-2147483648..2147483647;{ 16#80000000..16#7FFFFFFF }
1.6 – INTEGER64
The INTEGER64 predefined type is equivalent to the following: Syntax: INTEGER64=[QUAD]-9223372036854775808..9223372036854775807; { 16#8000000000000000..16#7FFFFFFFFFFFFFFF } The INTEGER64 predefined type is not available on OpenVMS VAX systems.
1.7 – UNSIGNED Types
VSI Pascal provides the UNSIGNED and UNSIGNED64 types (not available on all systems). Also provided are the UNSIGNED8, UNSIGNED16, UNSIGNED32, CARDINAL, CARDINAL16, and CARDINAL32 types, which are used as synonyms for the UNSIGNED type. The range of unsigned values consists of nonnegative integer values. The largest possible value of the UNSIGNED data type is represented by the predefined constant MAXUNSIGNED. The largest value for the UNSIGNED64 data type is represented by the predefined constant MAXUNSIGNED64. The smallest possible value for the UNSIGNED data type is 0.
1.8 – Standard Uns Radix
Extended digit notation allows you to express unsigned integer values in terms of a base number. VSI Pascal accepts numbers in bases 2 through 36. Syntax: [[ + | - ]] base-number#[[']]extended-digit[[']] The 'base-number' specifies the base of the number. The 'extended-digit' specifies the notation that is appropriate for the specified base. You can use extended-digit notation in the same way you use the conventional unsigned integer notation, except that extended-digit values cannot be used as labels. VSI Pascal allows the use of spaces and tabs to make the extended-digit notation easier to read. To use spaces and tabs, enclose the extended digit in single quotation marks (' '). The following are unsigned integer values in the extended-digit notation: 16#80000000 16#'8000 0000' 16#'FFFF FFFF'
1.8.1 – Nonstandard Uns Radix
VSI Pascal provides another extended integer convention only for the sake of compatibility with previous versions of the language. This notation specifies an unsigned integer in either binary (base 2), octal (base 8), or hexadecimal (base 16) notation. Syntax: b [[ + | - ]] % o [[']]extended-digit[[']] x The 'b', 'o', or 'x' specifies binary, octal, or hexidecimal notation, respectively. The 'extended-digit' specifies the notation that is appropriate for the specified base. The following are unsigned integer values in the VSI Pascal specific notation: %x'8000 0000' %x'FFFF FFFF'
1.9 – UNSIGNED8
The UNSIGNED8 data type is equivalent to the following: Syntax: TYPE UNSIGNED8 = [BYTE]UINT(0)..UINT(255); {0..16#FF}
1.10 – UNSIGNED16
The UNSIGNED16 data type is equivalent to the following: Syntax: TYPE UNSIGNED16 = [WORD]UINT(0)..UINT(65535); {0..16#FFFF}
1.11 – UNSIGNED32
The UNSIGNED32 data type is equivalent to the following: Syntax: TYPE UNSIGNED32 = [LONG]UINT(0)..UINT(4294967295); {0..16#FFFFFFFF}
1.12 – UNSIGNED64
The UNSIGNED64 data type is equivalent to the following (OpenVMS Alpha and OpenVMS I64 systems only): Syntax: TYPE UNSIGNED64 = [QUAD]UINT(0)..UINT(18446744073709551615); {0..16#FFFFFFFFFFFFFFFF}
1.13 – CHAR
The CHAR data type consists of single character values from the ASCII character set. The largest possible value of the CHAR data type is the predefined constant MAXCHAR. To specify a character constant, enclose a printable ASCII character in single quotation marks. To specify the single-quote character, enclose two single quotation marks in single quotation marks. Each of the following is a valid character constant: 'A' '0' {This is character 0, not the integer value 0} '''' {The apostrophe character} '?' You can specify nonprinting characters, such as a control-character, by writing an empty string followed immediately by the ordinal value of the character in the ASCII character set, or by using the CHR function followed by the ordinal value of the character in the ASCII character set. For example, both of the following specify the bell control character: ''(7) CHR(7)
1.14 – Boolean
Boolean values are the result of testing relationships for truth or validity. The Boolean data type consists of the two predeclared identifiers FALSE and TRUE. The expression ORD(FALSE) results in the value 0; ORD(TRUE) returns the integer 1.
1.15 – Enumerated
An enumerated type is a user-defined ordered set of constant values specified by identifiers. Syntax: ({enumerated-identifier},...) The 'enumerated-identifier' is an identifier of the enumerated type being defined. VSI Pascal allows a maximum of 65,535 identifiers in an enumerated type. The values of an enumerated type begin with the value 0 and follow a left-to-right order. Subsequent identifiers have a value one greater than the identifier preceding it. Example: X : ( Spring, Summer, Fall, Winter ) In this enumerated type, Spring (value 0) and Summer (value 1) are less than Fall (value 2) because they precede Fall in the list of constant values. Winter (value 3) is greater than Fall because it follows Fall. An identifier in an enumerated type cannot be defined for any other purpose in the same block.
1.16 – Subrange
A subrange type is user-defined and specifies a limited portion of another ordinal type (called the base type). The subrange syntax indicates the lower and upper limits of the type. Syntax: lower-bound..upper-bound The 'lower-bound' is a constant expression or a formal discriminant identifier that establishes the lower limit of the subrange. The 'upper-bound' is a constant expression or a formal discriminant identifier that establishes the upper limit of the subrange. The value of the upper bound must be greater than or equal to the value of the lower bound. The base type can be any enumerated or predefined ordinal type. The values in the subrange type appear in the same order as they are in the base type. For instance, the result of the ORD function applied to a value of a subrange type is the ordinal value that is associated with the relative position of the value in the base type, not in the subrange type. You can use a subrange type anywhere in a program that its base type is legal. A value of a subrange type is converted to a value of its base type before it is used in an operation. All rules that govern the operations performed on an ordinal type pertain to subranges of that type. Example: TYPE Day = ( Mon, Tues, Wed, Thurs, Fri, Sat, Sun ); Weekday = Mon..Fri; {subrange of base type Day} Digit = '0'..'9'; {subrange of base type CHAR} Month = 1 .. 31; {subrange of base type INTEGER} On OpenVMS Alpha and OpenVMS I64 systems, you cannot specify the size of INTEGER and UNSIGNED subranges to be larger than 32-bits eventhough such values would be legal in executable statements. For example: TYPE S = 0..8796093022208; is not supported, while VAR S : INTEGER64; BEGIN S := 8796093022208 END is legal.
2 – Real
Real types specify real number values with different degrees of precision.
2.1 – REAL
The REAL type denotes single-precision real values. The REAL type is synonymous with the SINGLE type. The largest REAL value is denoted by MAXREAL. The smallest REAL value is denoted by MINREAL. EPSREAL denotes the result of subtracting 1.0 from the smallest REAL value that is greater than 1.0. Example: 2.4 2.3e2 {exponential notation} On OpenVMS VAX systems, REAL uses the F_Floating format. On OpenVMS Alpha systems, REAL can take one of two formats: F_Floating and IEEE S_Floating. To specify a format, use either the FLOAT attribute or the /FLOAT command line qualifier. The default format on OpenVMS VAX and OpenVMS Alpha systems is F_Floating. The default format on OpenVMS I64 systems is IEEE S_Floating. On OpenVMS I64 systems, F_Floating is supported by converting to/from IEEE S_Floating for all floating point operations.
2.2 – SINGLE
The SINGLE type denotes single-precision real values. The SINGLE type is synonymous with the REAL type.
2.3 – F_FLOAT
The F_FLOAT type denotes a F_Floating single-precision real value regardless of the setting of the FLOAT attribute or /FLOAT command line qualifier.
2.4 – S_FLOAT
The S_FLOAT type denotes a IEEE S_Floating single-precision real value regardless of the setting of the FLOAT attribute or /FLOAT command line qualifier. S_FLOAT is supported on OpenVMS Alpha and OpenVMS I64 systems only.
2.5 – DOUBLE
The DOUBLE type denotes double-precision real values. To indicate a double-precision real number, you must include a real number or an integer, the letter D (or d), and an integer exponent with its minus sign or optional plus sign. The largest DOUBLE value is denoted by MAXDOUBLE. The smallest DOUBLE value is denoted by MINDOUBLE. EPSDOUBLE denotes the result of subtracting 1.0d0 from the smallest DOUBLE value that is greater than 1.0d0. Example: 0D0 4.371528665D-3 On OpenVMS VAX systems, DOUBLE exists in two formats: D_Floating and G_Floating. On OpenVMS Alpha and OpenVMS I64 systems, DOUBLE exists in three formats: D_Floating, G_Floating, and IEEE T_Floating. To specify a format, you can use either the FLOAT attribute or the /FLOAT command line qualifier. On OpenVMS VAX systems, the default format is D_Floating. On OpenVMS Alpha systems, the default format is G_Floating. On OpenVMS I64, the default format is IEEE T_Floating.
2.6 – D_FLOAT
The D_FLOAT type denotes a D_Floating double-precision real value regardless of the setting of the FLOAT attribute or /FLOAT command line qualifier.
2.7 – G_FLOAT
The G_FLOAT type denotes a G_Floating double-precision real value regardless of the setting of the FLOAT attribute or /FLOAT command line qualifier.
2.8 – T_FLOAT
The T_FLOAT type denotes an IEEE T_Floating double-precision real value regardless of the setting of the FLOAT attribute or /FLOAT command line qualifier. T_FLOAT is supported only on OpenVMS Alpha and OpenVMS I64 Systems.
2.9 – QUADRUPLE
The QUADRUPLE type denotes quadruple-precision real values. To indicate a quadruple-precision real number, you must include a real number or an integer, the letter Q (or q), and an integer exponent with its minus sign or optional plus sign. The largest QUADRUPLE value is denoted by MAXQUADRUPLE. The smallest QUADRUPLE value is denoted by MINQUADRUPLE. EPSQUADRUPLE denotes the result of subtracting 1.0q0 from the smallest QUADRUPLE value that is greater than 1.0q0. Example: 0.11435Q3 3362Q2 0.11825q-4 On OpenVMS VAX systems, QUADRUPLE uses the H_Floating format. On OpenVMS Alpha and OpenVMS I64 systems, QUADRUPLE uses the X_Floating format.
2.10 – H_FLOAT
The H_FLOAT type denotes quadruple-precision real values. The H_FLOAT type is synonymous with the QUADRUPLE type on OpenVMS VAX systems. H_FLOAT is supported only on OpenVMS VAX Systems.
2.11 – X_FLOAT
The X_FLOAT type denotes quadruple-precision real values. The X_FLOAT type is synonymous with the QUADRUPLE type on OpenVMS Alpha and OpenVMS I64 systems. X_FLOAT is supported only on OpenVMS Alpha and OpenVMS I64 systems.
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. A pointer type has the following syntax: [[attribute-list]] ^ [[attribute-list]] base-type-identifier The 'attribute-list' is one or more optional identifiers that provide additional information about the base type. The 'base-type-identifier' is the type identifier of the dynamic variable to which the pointer type refers. (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. Instead, you access them indirectly with pointers. Call the NEW procedure to allocate storage for dynamic variables. Call the DISPOSE procedure to deallocate this storage. Example: TYPE Reservation = RECORD Name : VARYING[30] OF CHAR; Class : ( standby, coach, first ); Flight_number : INTEGER; Next_passenger : ^Reservation; END; VAR Ticket : Reservation; In this example, 'Next_passenger' is a pointer to the record type 'Reservation'. The variable 'Ticket' is declared as type 'Reservation'. By manipulating the pointer variable, 'Ticket.Next_passenger', a linked list of records can be created using these definitions. By default, all pointer types are 32-bits wide. The NEW procedure uses LIB$GET_VM to allocate memory and LIB$FREE_VM to dispose of memory. On OpenVMS Alpha and OpenVMS I64, the [QUAD] attribute may be specified before the "^" character resulting in a 64-bit pointer. Using 64-bit pointers causes the NEW and DISPOSE procedures to LIB$GET_VM_64 to allocate memory and LIB$FREE_VM_64 to dispose of memory, respectively.
3.1 – C_STR_T
The C_STR_T predefined type is provided to interface with routines written in the C language using null-terminated strings. C_STR_T behaves like a normal pointer type in that you can assign NIL into it and the optional pointer checking code will check for dereferencing of a NIL pointer. The individual characters can be used by dereferencing the pointer and using an array index. No bounds checking will be performed even if array bounds checking is enabled. You cannot dereference a C_STR_T pointer without also indexing a single character. If you want to access an entire null-terminated string, see the PAS_STR function.
3.2 – POINTER
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: o To assign to or from any other type of pointer, including function result variables o To compare equality with any other type of pointer o To pass actual parameters of type POINTER to VAR and value parameters of any other type of pointer o To accept parameters of any other type of pointer with formal parameters of type POINTER
3.3 – UNIV_PTR
The predefined UNIV_PTR type is equivalent to: TYPE UNIV_PTR = POINTER;
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. See the "HP Pascal Language Reference Manual" for examples of valid constructors and examples that show how to assign values to individual components of structured objects.
4.1 – RECORD
A record is a group of components (called fields) that can be of various data types. Each record component may contain one or more data items. Syntax: [[PACKED]] RECORD [[field-list]] END END If field-list is not specified, an empty record is created. The following is an example of a record type: RECORD Part : INTEGER; Received : RECORD Month : ( Jan, Feb, Mar, Apr, May, June, Jul, Aug, Sep, Oct, Nov, Dec ); Day : 1..31; Year : INTEGER; END; END;
4.1.1 – Field list
The syntax for a field-list is as follows: { {{field-identifier},... : [[attribute-list]] type};... [[; variant-clause]] [[;]] variant-clause [[;]] } The 'field-identifier' is the name of a field. The 'attribute-list' is one or more optional identifiers that provide additional information about the field. The 'type' is the type of the corresponding field. A field can be of any type. The 'variant-clause' is the variant part of a record. A variant can contain different types or amounts of data at different times during program execution. The syntax for a variant clause is as follows: CASE { [[tag-identifier : ]] [[attribute-list]] tag-type-identifier}| discriminant-identifier } OF {{case-label-list} : (field-list)};... [[ [[;]] OTHERWISE (field-list)]] The 'tag-identifier' is the name of the tag field. The tag field is all of the elements between the reserved words CASE and OF. The 'attribute-list' is one or more optional identifiers that provide additional information about the variant. The 'tag-type-identifier' is the type identifier for the tag field. The 'discriminant-identifier' is 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. The 'case-label-list' consists of one or more constant values of the tag field type either separated by commas. A case constant is either a single constant value (for example, 1) or a range of values (for example, 5..10). The 'field-list' consists of 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. '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 following is an example of a variant record: 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.
4.1.2 – Standard record constructor
Record constructors are lists of values that you can use to initialize a record. Syntax: [[data-type]] [ [[{{component},... : component-value};... ]] [[{CASE [[tag-identifier :]] tag-value OF [{{component},... : component-value};... ] OTHERWISE ZERO [[;]] }]] ] The '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. The '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.) The 'component-value' specifies a value same data type as the component. These values are compile-time values; 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. The '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. The '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 last component in the constructor. When you specify constructors for a record that contains nested records, specify the type of the outermost record, but do not specify the type of the constructors for any nested records. The following are examples of record variables and possible standard record constructors: Example: TYPE Player_Rec = RECORD Wins : INTEGER; Losses : INTEGER; Percentage : REAL; END; VAR Player1 : Player_Rec VALUE [Wins: 18; Losses: 3; Percentage: 21/18] This record constructor appears in the variable declaration section, so the constructor type is optional, and compile-time values are required. Example: TYPE Player_Rec = RECORD Wins : INTEGER; Losses : INTEGER; Percentage : REAL; END; VAR Player1, Player2 : Player_Rec; {In the executable section} Player1 := Player_Rec[Wins:18; Losses: y; Percentage: Y+18/18]; This record constructor appears in the executable section, so the constructor type is required and run-time expressions are legal.
4.1.3 – Nonstandard record constructor
Syntax: [[data-type]] ([[{component-value},...]] [[tag-value, {component-value},...]]) The '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. The '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 component, and so forth. The '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). The following is an example of a record variable and a possible nonstandard record constructor: Rec : RECORD Person : VARYING [30] OF CHAR; Address : RECORD Number : INTEGER; Street : VARYING [30] OF CHAR; Zip : 0..9999; END; Age : 0..150: END; ('Blaise Pascal', (1623, 'Pensees Street', 91662), 39)
4.2 – ARRAY
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. Syntax: [[PACKED]] ARRAY [ {[[attribute-list]] index-type},... ] OF [[attribute-list]] component-type The 'attribute-list' is one or more optional identifiers that provide information about the component type. The 'index-type' is the type of the index, which can be any ordinal type or discriminated ordinal schema type. The 'component-type' is the type of the array components, which can be any type. The components of an array can be another array. Example: ARRAY [0..4] OF INTEGER An array, whose components are themselves arrays, is called a multidimensional array. An array can have any number of dimensions, and each dimension can have a different index type. Example: ARRAY [0..4, 'A'..'D'] OF INTEGER This array is declared as two-dimensional. To refer to a component of this two-dimensional array, specify the variable name followed by the two bracketed index values. For example X[0,'A'] or X[0]['A'] specify the component in 'X' at position '0', 'A'.
4.2.1 – Standard array constructor
Array constructors are lists of values that you can use to specify an array value. Syntax: [[data-type]] [ [[{{{component | component-subrange}},... : component-value};... ]] [[OTHERWISE component-value [[;]] ]] ] The '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. The 'component' or a '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. The '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. When you specify constructors for multidimensional arrays in the executable section, only specify the type of the outermost array.
4.2.1.1 – Examples
The following examples show possible constructors for the array Numbers: VAR Numbers : Count VALUE [1..3,5 : 1; 4,6 : 2; 7..9 : 3; 10 : 6]; {or, in the executable section} 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. Numbers := Count[4,6 : 2; 7..9 : 3; 10 : x+3; OTHERWISE 1]; To specify constructor values for all remaining elements, you can use the OTHERWISE clause.
4.2.2 – Nonstandard array constructor
Syntax: [[data-type]] ([[{component-value},...]] [[REPEAT component-value]]) The '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. The '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 instance, 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. The following is an example of an array variable and a possible array constructor: Result : ARRAY [1..2, 0..4] OF INTEGER; ((0,1,2,3,4),(5,6,7,8,9))
4.3 – SET
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. Syntax: [[PACKED]] SET OF [[attribute-list]] base-type The 'attribute-list' is one or more optional identifiers that provide additional information about the base type. The 'base-type' is the ordinal type identifier or type definition, or discriminated schema type, from which the set elements are selected. Note that real numbers cannot be elements of a set type. Example: SET OF CHAR Some possible set constructors for this set type are: ['A, 'E', 'I', 'O', 'U'] ['B'..'D', 'F'..'H', 'J'..'N', 'P'..'T', 'V'..'Z']
4.3.1 – Set constructor
Set constructors are lists of values that you can use to initialize a set. The syntax for set constructors is as follows: [[data-type]] [ [[{component-value},...]] ] The 'data-type' is 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. The '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, 95 or x+95, and integers between 110 and 115, inclusive. If the expression x+95 evaluates to an integer outside the range 35..115, then VSI Pascal includes no set element for that expression.
4.4 – File
A file is a sequence of components of the same type. The number of components is not fixed, so a file can be any length. The FILE type definition identifies the component type. Syntax: [[PACKED]] FILE OF [[attribute-list]] component-type The 'attribute-list' is one or more optional identifiers that provide additional information about the file components. The 'component-type' is the type of the file components which can be any ordinal, real, pointer, or structured type, except for the following: o A nonstatic type o A structured type with a nonstatic component o A file type o A 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. Example: FILE OF Boolean This example shows a file of Boolean values. If a variable, 'TRUTHS', is declared of this type, the file buffer is denoted by TRUTHS^.
4.4.1 – Text file
VSI Pascal supplies a predefined file type called TEXT. Files of type TEXT are 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 (using READLN, WRITELN, or EOLN), if you choose. The predeclared file variables INPUT and OUTPUT are files of type TEXT. They refer to the standard input and output files. The file type FILE OF CHAR differs from TEXT files in that FILE OF CHAR allows a single character to be the unit of transfer between a program and its associated I/O devices and that FILE OF CHAR files do not include special markers. FILE OF CHAR components are always read with the READ procedure, and must be read exclusively into variables of type CHAR, including CHAR components of structured variables. You cannot use the EOLN, READLN, and WRITELN routines on FILE OF CHAR files.
4.4.2 – External and internal files
VSI Pascal makes distinctions between external and internal files. An internal file has a name in a directory and exists outside the context of a VSI Pascal program. An internal file has no name and is not retained after the program finishes execution. A file declared in the program heading is external by default. A file declared in a nested block is internal by default. To change the default for internal files, call the OPEN procedure or specify a filename on the EXTEND, RESET, or REWRITE procedures. The file is then considered external and is retained with the specified name after the program has finished execution. If you open an internal file with the EXTEND, RESET, or REWRITE procedure, the file remains an internal file.
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. Syntax: schema-identifier ({discriminant-identifier},... : [[attribute-list]] ordinal-type-name};...) = [[attribute-list]] type-denoter; The 'schema-identifier' is the name of the schema. The 'discriminant-identifier' is the name of a formal discriminant. The 'ordinal-type-name' is the type of the formal discriminant, which must be an ordinal type. The 'attribute-list' is one or more identifiers that provide additional information about the type-denoter. The 'type-denoter' is 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 it is used to determine type compatibility. Discriminant identifiers can appear anywhere a value is required in this definition. TYPE Array_Template( Upper_Bound : 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. Actual discriminants can be compile-time 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.
5.1 – Discriminated Schema
A discriminated schema is a schema type that has been provided actual discriminants. Discriminated schema can appear in either the TYPE or the VAR sections. For example: TYPE Array_Template( Upper_Bound : INTEGER ) VAR Array_Type1 : Array_Template( 10 ); {ARRAY [1..10] OF INTEGER;} Array_Type2 : Array_Template( x ); {Upper boundary determined at run-time by variable or function call} In this example, the actual discriminants 10 and x complete the boundaries for Array_Template, forming two complete data types within the same schema type family. The type specifiers Array_Template( 10 ) and Array_Template( x ) are examples of discriminated schema.
5.2 – Undiscriminated Schema
An undiscriminated schema is a schema type that has not been provided actual discriminants. You can use an undiscriminated schema as the domain type of a pointer or as the type of a formal parameter. For example: TYPE Ptr_to_Array_Template = ^Array_Template; Array_Template( Upper_Bound : INTEGER ) 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.
6 – String Types
You can use schema and data types to store and to manipulate character strings. These types have the following order of complexity: 1. CHAR type 2. PACKED ARRAY OF CHAR user-defined types 3. VARYING OF CHAR user-defined types 4. STRING predefined schema Objects of the CHAR data type are character strings with a length of 1 and are lowest in the order of character string complexity. You can assign CHAR data to variables of the other string types. The PACKED ARRAY OF CHAR types allow you to specify fixed-length character strings. The VARYING OF CHAR types are a VSI Pascal extension that allows you to specify varying-length character strings with a constant maximum length. The STRING types provide a standard way for you to specify storage for varying-length character strings with a maximum length that can be specified at run time. To provide values for variables of these types, you should use a character-string constant (or an expression that evaluates to a character string) instead of an array constructor. Using array constructors with STRING and VARYING OF CHAR types generates an error; to use array constructors with PACKED ARRAY OF CHAR types, you must specify component values for every element in the array (otherwise, you generate an error). Example: VAR String1 : VARYING[10] OF CHAR VALUE 'abc';
6.1 – String
The STRING predefined schema provides a way of declaring variable-length character strings. The compiler stores STRING data as though it were stored in the following schema definition: TYPE STRING ( Capacity : INTEGER ) = VARYING[Capacity] OF CHAR; The syntax of the discriminated schema is as follows: STRING ( Capacity ) The 'Capacity' is an integer in the range 1..65,535 that indicates the length of the longest possible string. To use the predefined STRING schema, you provide an upper bound as the actual discriminant. Consider the following example: VAR Short_String : STRING( 5 ); {Maximum length of 5 characters} Long_String : STRING( 100 ); {Maximum length of 100 characters} You can assign string constants to STRING variables from length 0 to the specified upper bound. The compiler allocates enough storage space to hold a string of the maximum length. A STRING variable with length 0 is the empty string (''). You can only use character-string constants (or expressions that evaluate to character strings) to assign values to variables of these types; you cannot use standard array constructors. You can access the CAPACITY predeclared identifier as you would a schema discriminant, and you can access the LENGTH and BODY predeclared identifiers as you would access fields of a record. The CAPACITY identifier allows you to access the actual discriminant of the STRING schema; the LENGTH identifier allows you to access the current length of the string object; and the BODY identifier contains the current string object, including whatever is in memory up to the capacity of the discriminated schema.
6.2 – PACKED
User-defined packed arrays of characters with specific lower and upper bounds provide a method of specifying fixed-length character strings. The string's lower bound must equal 1. The upper bound establishes the fixed length of the string.
6.2.1 – Examples
The following example shows a declaration of a character string variable of twenty characters: VAR My_String : PACKED ARRAY[1..20] OF CHAR; Note that if the upper bound of the array exceeds 65,535, if the PACKED reserved word is not used, or if the array's components are not byte-sized characters, the compiler does not treat the array as a character string.
6.3 – Varying of char
The VARYING OF CHAR user-defined types are a VSI Pascal extension that provides a way of declaring variable-length character strings with a compile-time maximum length. If you require portable code, use the STRING predefined schema types to specify variable-length character strings. Syntax: VARYING [upper-bound] OF [[attribute-list]] CHAR The 'upper-bound' is an integer in the range from 1 through 65,535 that indicates the length of the longest possible string. The 'attribute-list' is one or more optional identifiers that provide additional information about the VARYING OF CHAR string components. To assign values to fixed-length character strings, you can use a character-string constant (or an expression that evaluates to a character string). When assigning into fixed-length strings, the compiler adds blanks to extend a string shorter than the maximum characters declared. If you specify a string longer than the maximum characters declared, an error occurs. You can also use an array constructor as long as you specify characters for every component of the array as specified in the declaration. Although a VARYING OF CHAR is a distinct type, it possesses some of the properties of both record and array types. A VARYING string is actually stored as though it were a record with two fields, LENGTH and BODY (which are predeclared identifiers in VSI Pascal). The LENGTH field contains the length of the current character string; the BODY field contains the string. Either field can be accessed in the same way record fields are accessed (VARY.LENGTH, VARY.BODY). Example: VARYING [25] OF CHAR This VARYING OF CHAR type could have the following values: 'Wolfgang Amadeus Mozart' 'Bach'
7 – Misc Types
VSI Pascal provides a predefined data types that can be used with specific routines.
7.1 – TIMESTAMP
The TIMESTAMP predefined type is used in conjunction with the GETTIMESTAMP procedure or with the DATE or TIME functions. GETTIMESTAMP initializes a variable of type TIMESTAMP; DATE and TIME function results are of type TIMESTAMP.