HP 3000 Manuals

Data Types [ HP Pascal/iX Reference Manual ] MPE/iX 5.0 Documentation


HP Pascal/iX Reference Manual

Data Types 

Figure 11-2  summarizes the types that are supplied by the system
programming extensions.  A detailed discussion of the data types follows
in this chapter.  This figure augments the HP Pascal data types
summarized in Figure 11-1 .  Note that the HP Pascal predefined data
types are highlighted.

[]
Figure 11-2. Extended Data Types Structured Types CRUNCHED. In Pascal, a structure (array, record, or set) can be unpacked or packed. Packed structures are declared by specifying the reserved word PACKED at the start of a structured type declaration. The system programming extensions define a third type of packing in addition to unpacked and packed, namely CRUNCHED. The reserved word CRUNCHED indicates that the components of a structured type (array, record, or set) are allocated contiguously, first to last, in a bit-aligned fashion with no intervening unused bits. Syntactically, the word CRUNCHED may be substituted for the word PACKED. The primary purpose of crunched packing is to provide a map from data item type to data representation that is independent of the implementation and the packing algorithm. For that reason, machine dependent types such as real, longreal, and file are not allowed in crunched structures. Example TYPE rec = RECORD a : type_a; b : type_b; c : type_c; END; crec = CRUNCHED RECORD a : type_a; b : type_b; c : type_c; END; In a crunched structure, each component is allocated the minimum number of bits required to represent that type, and each component is aligned in such a way that there are no unused bits between it and the previous component. The first declaration for rec in the previous example may lead to the following storage allocation for an arbitrary processor:
[]
Figure 11-3. Layout of a Record Note that there are unused bits between the fields a and b, and between the fields b and c. The crunched record declaration for crec, that is identical to the uncrunched record rec with the addition of the reserved word CRUNCHED, would lead to the following storage allocation:
[]
Figure 11-4. Layout of a Crunched Record Note that there are no wasted bits between fields in the crunched record. The number of bits used to represent each component of a crunched structured type is the minimum needed to represent the values associated with that component. The calculation of the minimum number of bits for various types is: * Record, Array Types. The sum of the minimum number of bits required to represent each component. If the record has variants, consider the size of the largest variant. * Set Types (of the form set of low .. high). The ordinal value of high minus the ordinal value of low plus one: ord(high) - ord(low) + 1 * Char and Enumeration Based Types (of the form low .. high). The next larger integer (the ceiling) of the logarithm base 2 of the successor of the ordinal value of the upper bound, or one, whichever is greater: max( ceil [ log2( ord(high) + 1 ) ], 1 ) Integer Based Types (of the form low .. high) The next larger integer (the ceiling) of the logarithm base 2 of the maximum of the absolute value of the ordinal value of the lower bound, and the successor of the absolute value of the ordinal value of the upper bound, or one, whichever is greater: max( ceil [ log2( max( |low|, |high| + 1 ) ) ], 1 ) If the type is signed (the lower bound is less than zero), then add one to the size. Table 11-3 shows the lower and upper bound ranges and number of bits allocated for unsigned subranges. Table 11-4 gives the same information for signed subranges. Table 11-3. Number of Bits Allocated for Unsigned Subranges ----------------------------------------------------------------------------------------------- | | | | | Lower Bound Range | Upper Bound Range | # Bits Allocated | | | | | ----------------------------------------------------------------------------------------------- | | | | | >= 0 | 0..1 | 1 | | >= 0 | 2..3 | 2 | | >= 0 | 4..7 | 3 | | >= 0 | 8..15 | 4 | | >= 0 | 16..31 | 5 | | >= 0 | 32..63 | 6 | | >= 0 | 64..127 | 7 | | >= 0 | 128..255 | 8 | | >= 0 | 256..511 | 9 | | >= 0 | 512..1023 | 10 | | >= 0 | 1024..2047 | 11 | | >= 0 | 2048..4095 | 12 | | >= 0 | 4096..8191 | 13 | | >= 0 | 8192..16383 | 14 | | >= 0 | 16384..32767 | 15 | | >= 0 | 32768..65535 | 16 | | >= 0 | 65536..131071 | 17 | | >= 0 | 131072..262143 | 18 | | >= 0 | 262144..524287 | 19 | | >= 0 | 524288..1048575 | 20 | | >= 0 | 1048576..2097151 | 21 | | >= 0 | 2097152..4194303 | 22 | | >= 0 | 4194304..8388607 | 23 | | >= 0 | 8388608..16777215 | 24 | | >= 0 | 16777216..33554431 | 25 | | >= 0 | 33554432..67108863 | 26 | | >= 0 | 67108864..134217727 | 27 | | >= 0 | 134217728..268435455 | 28 | | >= 0 | 268435456..536870911 | 29 | | >= 0 | 536870912..1073741823 | 30 | | >= 0 | 1073741824..2147483647 | 31 | | | | | ----------------------------------------------------------------------------------------------- Table 11-4. Number of Bits Allocated for Signed Subranges ---------------------------------------------------------------------------------------------- | | | | | Lower Bound Range | Upper Bound Range | #Bits Allocated | | | | | ---------------------------------------------------------------------------------------------- | | | | | -1 | 0 | 1 | | -2 | 1 | 2 | | -4..-3 | 2..3 | 3 | | -8..-5 | 4..7 | 4 | | -16..-9 | 8..15 | 5 | | -32..-17 | 16..31 | 6 | | -64..-33 | 32..63 | 7 | | -128..-65 | 64..127 | 8 | | -256..-129 | 128..255 | 9 | | -512..-257 | 256..511 | 10 | | -1024..-513 | 512..1023 | 11 | | -2048..-1025 | 1024..2047 | 12 | | -4096..-2049 | 2048..4095 | 13 | | -8192..-4097 | 4096..8191 | 14 | | -16384..-8193 | 8192..16383 | 15 | | -32768..-16385 | 16384..32767 | 16 | | -65536..-32769 | 32768..65535 | 17 | | -131072..-65537 | 65536..131071 | 18 | | -262144..-131073 | 131072..262143 | 19 | | -524288..-262145 | 262144..524287 | 20 | | -1048576..-524289 | 524288..1048575 | 21 | | -2097152..-1048577 | 1048576..2097151 | 22 | | -4194304..-2097153 | 2097152..4194303 | 23 | | -8388608..-4194305 | 4194304..8388607 | 24 | | -16777216..-8388609 | 8388608..16777215 | 25 | | -33554432..-16777217 | 16777216..33554431 | 26 | | -67108864..-33554433 | 33554432..67108863 | 27 | | -134217728..-67108865 | 67108864..134217727 | 28 | | -268435456..-134217729 | 134217728..268435455 | 29 | | -536870912..-268435457 | 268435456..536870911 | 30 | | -1073741824..-536870913 | 536870912..1073741823 | 31 | | -2147483648..-1073741825 | 1073741824..2147483647 | 32 | | | | | ---------------------------------------------------------------------------------------------- Example TYPE cr1_t = CRUNCHED RECORD f1 : 0..15; { takes 4 bits } f2 : -1..15; { takes 5 bits } f3 : -16..15; { takes 5 bits } f4 : 13..15; { takes 4 bits } END; { total: 18 bits } cr2_t = CRUNCHED RECORD f1 : CRUNCHED set of 0..15; { takes 16 bits } f2 : CRUNCHED set of 13..15; { takes 3 bits } f3 : CRUNCHED set of -5..5; { takes 11 bits } END; { total: 30 bits } cr3_t = CRUNCHED RECORD f1 : integer; { takes 32 bits } CASE tag : Boolean OF { takes 1 bit } true: ( v1 : cr1_t ); { takes 18 bits } false:( v2 : cr2_t ); { takes 30 bits } END; { total: 63 bits } The restrictions that apply to packed types also apply to crunched types. In particular, it is illegal: * To pass a component of a crunched structure as a reference parameter. * To take the address of a component of a crunched structure. In addition: * File types cannot be crunched. * Structured types that contain file, real, longreal, string, or pointer types cannot be crunched. * All structured types contained in a crunched structured type must also be crunched. * All integer based types and enumeration based types are represented with the most significant bit first through least significant bit last. Byte swapping is not permitted. Pointer Types In HP Pascal, pointers are designators that point only to a specific class of objects, namely objects on the heap. When using the system programming extensions, pointers can point to any data; that is, objects on the heap, as well as global and local variables. In this sense pointers truly are addresses. In HP Pascal, the only way to create a pointer is by calling the predefined procedure NEW or the intrinsic getheap to dynamically allocate a heap object. In order to create pointers, the system programming extensions define the addr function that returns the address of its argument, and the functions buildpointer and addtopointer that perform address arithmetic. There are three predefined pointer types defined in the system programming extensions that allow relaxed type checking of pointers. These are anyptr, localanyptr, and globalanyptr. Short and Long Pointers. The system programming extensions define two classes of pointers: short and long pointers. Long pointers can point to any addressable object on the system (in this sense addressable in terms of the representability of an address, as opposed to allowed access rights). Short pointers can point to a subset of the objects addressable by long pointers. A subset of the object addressable by short pointers are objects in the heap. By default, all user declared pointers are short pointers. The following diagram explains the relationship between these classes of pointers.
[]
Figure 11-5. Pointer Class Relationship Note that in some implementations, long and short pointers may be identical; in other words, the collection of objects that long and short pointers can point to may be the same. The compiler option EXTNADDR can be used to specify that a given user defined pointer type is to be a long pointer. Localanyptr. The predefined type localanyptr is a pointer type that is assignment compatible with any other pointer type. It can be used to defeat type checking on pointers. A pointer of any type can be assigned to a pointer of type localanyptr, and a pointer of type localanyptr can be assigned to any pointer type. However, since pointers of type localanyptr are not bound to a base type, they cannot be dereferenced. (In order to dereference a pointer of type localanyptr, it must first be type coerced or assigned to a proper pointer type). localanyptr takes the form of a short pointer. It may only be able to represent a subset of the addresses on a machine. On implementations where short and long pointers are not the same, localanyptr is more efficient than globalanyptr. Permissible Operators assignment := relational =, <> Example VAR ptr1 : pointer_type_1; ptr2 : pointer_type_2; anyp : localanyptr; BEGIN ... anyp := ptr1; anyp := ptr2; ... ptr1 := anyp; ... END; Globalanyptr. The predefined type globalanyptr is a pointer type that is assignment compatible with any other pointer type. It can be used to defeat type checking on pointers. A pointer of any type can be assigned to a pointer of type globalanyptr, and a pointer of type globalanyptr can be assigned to any pointer type. However, since pointers of type globalanyptr are not bound to a base type, they cannot be dereferenced. (In order to dereference a pointer of type globalanyptr, it must first be type coerced or assigned to a proper pointer type.) Globalanyptr takes the form of a long pointer. It can represent any address on the machine. A more efficient type of pointer called localanyptr can be used in a program that has no need for long pointers. Permissible Operators assignment := relational =, <> Example VAR ptr1 : pointer_type_1; ptr2 : pointer_type_2; anyp : globalanyptr; BEGIN ... anyp := ptr1; anyp := ptr2; ... ptr1 := anyp; ... END; Anyptr. The predefined type anyptr is a pointer type that is assignment compatible with any other pointer type. It can be used to defeat type checking on pointers. A pointer of any type can be assigned to a pointer of type anyptr, and a pointer of type anyptr can be assigned to any pointer type. However, since pointers of type anyptr are not bound to a base type, they cannot be dereferenced. In order to dereference a pointer of type anyptr, it must first be type coerced or assigned to a proper pointer type. Anyptr takes the form of a long pointer. It can represent any address on the machine. A more efficient type of pointer called localanyptr can be used in a program that has no need for long pointers. Anyptr is equivalent to globalanyptr; however, globalanyptr and localanyptr are the recommended types to use. Permissible Operators assignment := relational =, <> Example VAR ptr1 : pointer_type_1; ptr2 : pointer_type_2; anyp : anyptr; BEGIN ... anyp := ptr1; anyp := ptr2; ... ptr1 := anyp; ... END; The above example illustrates that a variable of type anyptr is assignment compatible with any other pointer type. Example VAR ptr1 : pointer_type_1; ptr2 : pointer_type_2; PROCEDURE proc( ptr : anyptr ); BEGIN ... END; BEGIN proc( ptr1 ); proc( ptr2 ); END; In the above example, the routine proc can accept any pointer as an actual parameter because the type of the formal parameter is anyptr. anyptr is assignment compatible with any pointer type. Example TYPE pointer_type = ^record_type; record_type = RECORD int : integer; END; VAR i : integer; anyp : anyptr; BEGIN i := pointer_type( anyptr )^.int; END; In the above example, the pointer anyp is dereferenced to access a field in a record. Since an anyptr is not bound to a base type, the pointer must first be type-coerced to a pointer type corresponding to the structure to which anyp is pointing. PROCEDURE and FUNCTION Types In Pascal, PROCEDURE and FUNCTION parameters allow dynamic reference to procedures and functions where the exact instance of the procedure or function is not known until run-time. The system programming extensions extend this concept to allow variables as well as parameters that refer to procedures and functions. Syntax
[]
A parallel can be drawn between pointers and PROCEDURE/FUNCTION variables. While pointers are variables that reference data, PROCEDURE/FUNCTION variables reference code. Variables of PROCEDURE/FUNCTION types may be assigned procedures and functions that have congruent parameter lists, as defined in HP Pascal. See chapter 8 for more information on parameters. To assign a procedure or function to a PROCEDURE/FUNCTION variable, the routine name is used as a parameter to the addr function. See the section on predefined routines in this chapter for more information on addr. Any procedure or function assigned must have the same or wider scope than the variable or value parameter to which it is assigned. Any PROCEDURE/FUNCTION variable passed as a reference parameter must have the same or wider scope than the formal parameter to which it is bound. A PROCEDURE/FUNCTION variable can be assigned NIL. The procedure or function referenced by a PROCEDURE/FUNCTION variable, may be invoked by calling the predefined procedure call for a PROCEDURE variable or the predefined function fcall for a FUNCTION variable. See the section on predefined routines in this chapter for more information on call and fcall. Permissible Operators assignment := relational =, <> Standard Procedures argument CALL Standard Functions argument FCALL return ADDR Example TYPE proc_0_type = PROCEDURE; func_0_type = FUNCTION: integer; proc_1_type = PROCEDURE( ANYVAR i : integer ); func_2_type = FUNCTION( VAR s : string; i : integer ): boolean; VAR proc_0 : proc_0_type; func_0 : func_0_type; proc_1 : proc_1_type; func_2 : func_2_type; PROCEDURE p1; external; PROCEDURE p2( n : shortint ); external; PROCEDURE p3( VAR i : integer ); external; BEGIN func_0 := nil; { initialized to nil } func_2 := nil; { initialized to nil } proc_0 := addr( p1 ); { proc_0 now 'points to' p1 } proc_1 := addr( p2 ); { illegal: parameters don't match } proc_1 := addr( p3 ); { illegal: parameters don't match } func_0 := addr( p1 ); { illegal: must be a function } END. Example TYPE proc_type = PROCEDURE; VAR proc_var_0 : proc_type; PROCEDURE proc_1; VAR proc_var_1 : proc_type; PROCEDURE proc_2; BEGIN {PROCEDURE proc_2} ... END; {PROCEDURE proc_2} BEGIN {PROCEDURE proc_1} proc_var_0 := addr( proc_1 ); proc_var_1 := addr( proc_1 ); proc_var_0 := addr( proc_2 ); { illegal: scoping violation } proc_var_1 := addr( proc_2 ); END; {PROCEDURE proc_1}


MPE/iX 5.0 Documentation