This chapter describes the Open PL/I language implementation for your system. For detailed information on the Open PL/I programming language, see your Open PL/I Language Reference Manual.
A line boundary consists of a new-line character (CRLF on a Windows system), and the line boundary in a quoted string constant is considered part of the string constant.
Exactly one of the external procedures that is linked into an executable file must specify the main entry point to the program by including the OPTIONS(MAIN) clause on the PROCEDURE statement. This designates that procedure as the main entry point at which execution should begin, after some run-time initialization has been completed. This option must appear even if the entire program is a single procedure contained in a single source file. Failure to specify a main program, or specifying more than one main program, will cause errors to occur during program linkage.
The main procedure is not required to be a PL/I procedure; that is, it can be written in another language.
The Open PL/I data types include the following:
Table 2-1 lists the data types, along with the alignment and size of their machine representations.
Alignment is the same for HP PA-RISC, Intel, RS/6000, and Sun SPARC, unless otherwise specified.
| Data Type | Size | Alignment: aligned data | Alignment: unaligned data |
|---|---|---|---|
| Fixed Binary ( p ≤ 7) 1 | 1 byte | 1 byte | byte |
| Fixed Binary (8 ≤ p ≤ 15) | 2 bytes | 2 bytes | byte |
| Fixed Binary (p > 15) | 4 bytes | 4 bytes | byte |
| Fixed Decimal (p,q) | [(p+2)/2] bytes | byte | byte |
| Float Binary (p ≤ 23) | 4 bytes | 4 bytes | byte |
| Float Binary (p > 23) | 8 bytes | 4 bytes (Intel),
8 bytes (non-Intel) | byte |
| Float Decimal (p) | 12 bytes | 4 bytes | byte |
| Character (n) | n bytes | byte | byte |
| Character (n) Varying | n+2 bytes | 2 bytes | byte |
| Bit (n) | n bits | bit | bit |
| Bit (n) Aligned | [(n+7)/8] bytes | byte | – |
| Pointer | 4 bytes | 4 bytes | byte |
| Picture | n bytes | byte | byte |
| Label | 8 bytes | 4 bytes | byte |
| Entry Variable | 8 bytes | 4 bytes | byte |
| File Variable | 4 bytes | 4 bytes | byte |
| Structure | sum of members + gaps for alignment | max of members | |
| Area (n) | (((n+7)/8)*8)+8 bytes | 8 bytes | – |
| Offset | 4 bytes | 4 bytes | byte |
Footnotes:
*Fixed Binary (p ≤ 7) is handled as a one-byte signed binary integer only if the -vax Compiler option is in effect. Otherwise, it is handled as Fixed Binary(15).
Subsequent sections provide additional information about the size, alignment, internal representation including byte ordering, and range, where applicable.
The byte ordering on the HP PA-RISC, IBM RS/6000, and Sun SPARC platforms is Big Endian, while the Intel-based platforms have Little Endian byte ordering.
Note: In the descriptions of data types that follow, the alignment specified is the default, which is ALIGNED for all data types except Bit. For the alignment of each data type with the UNALIGNED attribute, refer to Table 2-1, above.
Fixed Binary (p 7) is an 8-bit, signed, 2's complement binary integer. The low order 7 bits contain the integer, the high order bit contains the sign. The sign bit (S) is 1 if the value is negative, 0 if the value is positive or zero. This data type is available only when you use the -vax Compiler option.
| Size | Alignment | Range |
|---|---|---|
| 1 byte | 1 byte | -128 to 127 |
Fixed Binary (8 ≤ p ≤ 15) is a 16-bit, signed, 2's complement binary integer. The low order 15 bits contain the integer, the high order bit contains the sign. The sign bit (S) is 1 if the value is negative, 0 if the value is positive or zero.
| Size | Alignment | Range |
|---|---|---|
| 2 bytes | 2 bytes | -32768 to 32767 |
Fixed Binary (15 ≤ p ≤ 31) is a 32-bit, signed, 2's complement binary integer. The low order 31 bits contain the integer, the high order bit contains the sign. The sign bit (S) is 1 if the value represented is negative.
| Size | Alignment | Range |
|---|---|---|
| 4 bytes | 4 bytes | -2,147,483,648 to 2,147,483,647 |
Fixed Decimal (p,q) is a fixed-point number that contains p digits, where q of those digits are fraction digits. Fixed decimal values are typically used only when fraction digits are required. Fixed-point decimal values are always stored as an accurate representation of decimal fractions. The most significant digits are stored at the lowest memory address, and the byte containing the least significant digit and the sign (hexadecimal C for positive or D for negative) is stored at the highest memory address.
| Size | Alignment | Range |
|---|---|---|
| [(p+2)/2] bytes | byte | -(10p-q - 10-q) to +(10p-q -10-q |
Float Binary (p ≤ 23) is a single-precision, basic format, binary floating-point number (ASCII/IEEE 754-1985 compliant). It contains a 1-bit sign, 8-bit biased exponent (bias = 127), and 23+(1)-bit binary fraction (hidden bit).
An exponent of 255 represents +/- infinity or not-a-number. +/- infinity is represented by an exponent of 255 and zero as the fraction part; the sign bit denotes the + or - infinity. Not-a-number is represented by an exponent of 255 and any non-zero value in the fraction part; the sign bit of not-a-number is not significant. An exponent of 0 denotes a denormalized small value of reduced precision. Both +0 and -0 are possible. Note that the range is approximate and indicates representable values, which include zero and both negative and positive numbers.
| Size | Alignment | Approximate Absolute Value of Range |
|---|---|---|
| 4 bytes | 4 bytes | 1.40E-45 to 3.40E+38 |
Float Binary (23 < p ≤ 52) is a double-precision, basic format, binary floating-point number (ANSI/IEEE 754-1985 compliant). It consists of a 1-bit sign, 11-bit biased exponent (bias = 1023), and 52+(1)-bit binary fraction (hidden bit).
An exponent of 2047 represents +/- infinity or not-a-number. +/- infinity is represented by an exponent of 2047 and zero as the fraction part; the sign bit (S) denotes the + or - infinity. Not-a-number is represented by an exponent of 2047 and any non-zero value in the fraction part; the sign bit of not-a-number is not significant. An exponent of 0 denotes a denormalized value of reduced precision. Both +0 and -0 are possible. Note that the range is approximate and indicates representable values, which include zero and both negative and positive numbers.
| Size | Alignment | Approximate Absolute Value of Range |
|---|---|---|
| 8 bytes | 4 bytes (Little Endian)
8 bytes (Big Endian) |
4.9E-324 to 1.8E+308 |
For compatibility with IBM PL/I, data declared as float decimal is stored and processed by default as 4-byte or 8-byte float binary. (If the specified precision is ≤ 6, 4-byte float binary is used.)
Alternatively, float decimal data can be stored and processed as 12-byte Binary Coded Decimal BCD float decimal data by using the -nofdasfb ("no float dec as float bin") compiler option. In this case, Float Decimal (p) is a decimal floating-point number, stored in packed decimal format. It consists of a sign, an exponent sign, two bits used for infinity, not-a-number (usually 0), a 3-digit (base 10) exponent and a 17-digit (base 10) fraction. Both the exponent and fraction have a separate sign bit. All digits are packed Binary Coded Decimal (BCD), such that the entire string fits in 96 bits (12 bytes). The fraction contains at least p decimal digits.
| Size | Alignment | Approximate Absolute Value of Range |
|---|---|---|
| 12 bytes | 4 bytes | 9.9999999999999999x10 -999 to 9.9999999999999999x10 999 |
Character (n) is a character-string variable where n is an integer that specifies the length of the string value held by the variable. Character (n) is a sequence of 8-bit ASCll characters stored as 1 character per byte. In Open PL/I, the maximum length of a string variable is 32767 characters.
| Size | Alignment |
|---|---|
| n bytes | byte |
Character (n) Varying is a character-string variable. The VARYING attribute causes the string variable to hold values of varying length. The representation of a varying string variable in storage is such that any string up to n characters may be held by the variable, and the length of the current string is retained as part of the value. Character (n) Varying is stored as follows: the first two bytes contain the length of the string (represented by a Fixed Binary (15) number) followed by a sequence of 8-bit ASCII characters stored as 1 character per byte. In Open PL/I, the maximum length of a string value is 32767 characters.
Note that the character string is not terminated with a null (ASCII 0) character.
| Size | Alignment |
|---|---|
| n+2 bytes | 2 bytes |
Bit (n) is a bit-string variable where n is an integer valued expression that specifies the length of the string value held by the variable. Bit (n) is a sequence of binary digits (bits) that always occupies exactly n bits of storage.
If the last bit of the bit-string does not occur on a byte boundary, the remaining bits in the last byte might be part of another bit-string variable. Within each byte, the bits of the string are stored from the high-order to the low-order position. For example, Bit (23) would be stored as follows:
| Size | Alignment |
|---|---|
| n bits | bit (none) |
Bit (n) Aligned is a bit-string variable. The ALIGNED attribute causes the bit-string variable for which it is declared to be byte-aligned, resulting in more efficient access. This attribute may also cause the variable to occupy more than n bits, but it does not increase the length of the value that can be stored in the variable. The ALIGNED attribute has no effect on operations performed on the variable, but is considered part of the data type for purposes of argument/parameter matching and storage sharing.
Bit (n) Aligned size is in bytes. If the length, n, is not a multiple of eight (for example, Bit (27) Aligned) then the remaining bits in the last byte are unused. Within each byte, the bits of the string are stored from the high-order to the low-order position. For example, Bit (27) Aligned would be stored as follows:
| Size | Alignment |
|---|---|
| [(n+7)/8] bytes | byte |
Pointer is a 4-byte, 32-bit word variable capable of holding the address of any variable except unaligned bit variables. Pointers are normally used to locate the storage of dynamically allocated BASED variables rather than as a mechanism for accessing another variable's storage. A pointer is used with a template to access the storage to which it points. A pointer value cannot be represented by a constant. Pointer values can be assigned, compared for equality or inequality, passed as arguments, and returned from functions. No calculations or conversions can be performed on them, and they cannot be transmitted in stream I/O.
| Size | Alignment |
|---|---|
| 4 bytes | 4 bytes |
Label is an 8-byte, 32-bit word pair variable consisting of a 4-byte text address and a 4-byte frame pointer value. The text address identifies the first instruction of a labeled statement in the containing procedure. The frame pointer value identifies the address of the stack frame of the block containing the statement. Label values can be assigned, compared for equality or inequality, passed as arguments, and returned from functions. No calculations or conversions can be performed on them, and they cannot be transmitted in stream I/O.
| Size | Alignment |
|---|---|
| 8 bytes | 4 bytes |
Picture is a fixed-point decimal value stored internally as a character string. The string contains the characters that represent the numeric value, and may be formatted with special embedded symbols such as a period (.) or a comma (,). Picture data is best used to manipulate a quantity arithmetically and then print or display its value.
| Size | Alignment |
|---|---|
| n bytes | byte |
Entry is an 8-byte, 32-bit word pair variable consisting of a 4-byte descriptor pointer and a 4-byte frame pointer value. The descriptor pointer points to a data area that specifies the text address of the procedure entry and the table of contents pointer for the procedure. The frame pointer (relevant only with internal procedures) designates the stack frame of the containing procedure, if any. For external procedures, the frame pointer value is zero (0).
| Size | Alignment |
|---|---|
| 8 bytes | 4 bytes |
File Variable is represented internally as a 4-byte, 32-bit word containing the address of a file control block. When evaluated, the value of the file variable is the address of the file control block for the file with which the variable is associated. A file variable can be assigned any file value; it is declared using both the FILE and VARIABLE attributes.
| Size | Alignment |
|---|---|
| 4 bytes | 4 bytes |
Structure is a hierarchically ordered set of values that may be of different data types. The immediate components of a structure are called "members" of the structure. An entire structure can be transmitted in stream or record I/O, passed as an argument, or assigned to another structure of identical size and shape and having members of corresponding identical data types. No conversions or calculations can be performed on entire structures.
| Size | Alignment |
|---|---|
| Sum of members + gaps for alignment | Most stringent of members' alignment requirements |
Area (n) is a variable describing a region of storage whose size in bytes is defined by the integer n. An area variable is a region of storage in which based variables can be allocated and freed. An area can be passed as an argument or it can be assigned to another area. It can also be transmitted in its entirety in a record I/O operation. No other operations, calculations, or conversions can be performed on area variables.
| Size | Alignment |
|---|---|
| n bytes rounded to 8 byte boundary, plus 8 byte header [ (((n+7)/8)*8)+8] bytes | 8 bytes |
An offset variable is a locator used only in conjunction with an area variable. The value of an offset variable specifies the location of a based variable within an area, relative to the beginning of the area.
Offset variables can be assigned, compared for equality and inequality, passed as arguments, and returned as function results. No calculations or conversions can be performed on them, except in the context of explicit conversion to a Pointer, using Open PL/I's POINTER built-in function.
| Size | Alignment |
|---|---|
| 4 bytes | 4 bytes |
Each arithmetic data type has a default precision and a maximum precision as specified in Table 2-2. The range of the scale factor of fixed-point decimal data is 0 through 18 (0 ≤ q ≤ 18).
| Data Type | Maximum Precision | Default Precision |
|---|---|---|
| Fixed Binary | 31 | 15* |
| Fixed Decimal | 18 | 5 |
| Float Binary | 52 | 23 |
| Float Decimal | 16 | 6 |
* The -Iongint Compiler option changes the default precision of fixed binary from 15 to 31.
Open PL/I adheres to the calling conventions of the native architecture. Programs compiled by Open PL/I can be linked with object modules produced by other language products, and the resulting object program will run if the following conditions are met:
Certain rules apply with regard to name length and the use of lowercase letters when specifying an identifier name:
If Open PL/I is calling a C function or vice-versa, one of the following options is available.
The maximum number of arguments that may be passed in an Open PL/I program is given by the following formula, which holds generally for any function or subroutine call argument list:
N + M= 241
where:
| N | Is the actual number of arguments specified. |
| M | Is the position of the last *-extent argument, or zero if none exist |
DECLARE (S, T, U, V) CHAR (32),
(I, J, K, L) BINARY (15),
MYSUB ENTRY (BINARY(15), BINARY (15), CHAR(*),
CHAR(*), BINARY(15), BINARY(15));
.
.
.
CALL MYSUB(I,J,K,S,T,L);
where:
| N | = 6 (the number or arguments specified) |
| M | = 5 (the position of "T" in the argument list) |
which gives:
| N+ M | = 11 (6 actual arguments; 3 dummy descriptors for I, J, and K; and 2 actual descriptors for S and T). |
The following sections describe the calling conventions for HP, Intel, RS/6000, and Sun Sparc systems. All LPI-series languages compilers use the following calling conventions and are compatible with Open PL/I.
If you are calling a function written in another language, the result type must be able to be mapped to a PL/I data type.
C often expects character strings to be null terminated, that is, the string is delimited by an '\0' byte immediately following the last character of interest. When constructing a character value in PL/I that is passed to a C function expecting a null terminator, the PL/I procedure must supply an explicit null character in the appropriate position. The BYTE built-in function can be used for this purpose, as shown in the following example.
CFUNC('abcde' || BYTE(0))
or without the BYTE built-in,
CFUNC('abcde'Z)
The following program illustrates how to declare and call two standard C library functions, "atoi" and "strtol":
int atoi(const char *str) long strtol(const char *str, char **endptr, int base)
Please note the following points:
CALLC: PROCEDURE OPTIONS(MAIN);
DECLARE
ATOI ENTRY(CHARACTER(80))
RETURNS(FIXED BINARY(31))
EXTERNAL('atoi'),
ATOI_2 ENTRY(POINTER VALUE)
RETURNS(FIXED BINARY(31))
EXTERNAL('atoi'),
STRTOL ENTRY(CHARACTER(80),
POINTER VALUE,
FIXED BINARY(31) VALUE)
RETURNS(FIXED BINARY(31))
EXTERNAL('strtol'),
BASE FIXED BINARY(31),
ENDPTR POINTER,
INT FIXED BINARY(31),
LONG FIXED BINARY(31),
STR CHARACTER(80),
STRPTR POINTER;
STR = '2147483647'z;
INT = ATOI(STR);
PUT SKIP LIST(INT);
STRPTR = ADDR(STR);
INT = ATOI_2(STRPTR);
PUT SKIP LIST(INT);
STR = '0x7fffffff'z;
ENDPTR = SYSNULL();
BASE = 16;
LONG = STRTOL(STR, ENDPTR, BASE);
PUT SKIP LIST(LONG);
PUT SKIP LIST(STRTOL('0x7fffffff'z, SYSNULL(), 16));
END CALLC;
The following sections detail the argument passing conventions for HP, Intel, RS/6000, and Sun Sparc platforms.
Arguments are passed in General Purpose Registers (GR) 26–23, Single-Precision Floating-Point Registers (FR) 4–7, Double-Precision Floating-Point Registers (FR) 5 and 7, and in the parameter area of the stack, according to the Open PL/I standard calling conventions.
The external procedure is called by executing a CALL instruction.
Arguments are passed in General Purpose Registers (GPR) 3–10, Floating-point Registers (FPR) 1–13, and in the parameter area of the stack according to the Open PL/I standard calling conventions.
External procedures are called using the CALL instruction and are returned using the RET and RESTORE sequence.
The following sections detail the register save conventions for HP, Intel, and Sun Sparc systems.
The called procedure is expected to save and restore values in registers GR3–GR18 and FR12–FR21. The calling procedure can assume that those registers are preserved across the call. The function result is in GR28, FR4, or the result temporary provided by the caller, depending on the result data type. For more information, see the section HP Function Result Conventions.
The contents of ebx, esi, and edi must be preserved across a subroutine call. If a subroutine uses one of these registers, it must save the original value and restore it before returning to the caller.
Registers eax, ecx, and edx are scratch registers. A subroutine can change the value in a scratch register without saving its previous value.
When the Intel floating-point coprocessor is used, the floating-point stack registers must be empty before entry and upon exit from a subroutine. However, if the subroutine returns a floating-point value, the value is returned on top of the stack in register fp0 and the remainder of the stack is empty.
A called procedure is responsible for establishing a new stack frame for itself and saving and restoring all preserved registers. The procedure establishes the stack frame with the following sequence:
pushl ebp movl esp, ebp subl #framesize, esp pushl ebx //only if used within function pushl esi //only if used within function pushl edi //only if used within function
Note that the code sequence may be abbreviated if -opt is specified.
A return must store any function result value, restore any preserved registers it used, pop its stack frame, and return to the caller.
A procedure that returns one of the data types that requires a return temporary must remove the extra pointer(s) from the stack entry; callers to such routines push these hidden arguments. The called routine must load register eax with the pointer to the return area that its caller passed before returning. Such a routine will start with the following code before establishing a frame:
popl edx xchgl edx, 0 (esp)
Then it saves the return pointer in a local variable in its stack frame.
The called procedure is expected to save and restore values in registers GPR13 through GPR31 and FPR14 through FPR31. The calling procedure can assume that those registers are preserved across the call. The function result is in GPR3, FPR1, or the result temporary provided by the caller, depending on the result data type.
The called procedure is expected to save and restore all local and input registers (10 through 17 and i0 through i7). The calling procedure can assume that only these registers are preserved across the call. The function result is general ally in o0, f0, or both f0 and f1, or the result temporary provided by the caller, depending on the result data type. For more information, see the section Sun Sparc Function Result Conventions.
A called procedure is responsible for establishing a new stack frame for itself and saving and restoring all local and input registers. This is accomplished by a SAVE instruction. Before returning, the called procedure must store any function result value, restore all local and input registers, and adjust the stack frame. This is accomplished by a load of i0, f0, or both f0 and f1, or a store to a result temporary and a RESTORE instruction.
A function returns its result to the caller in one of four ways. The following sections detail the function result conventions on HP, Intel, RS/6000, and Sun Sparc systems.
A function procedure returns its result value to the calling procedure in one of three ways, depending upon the data type: in register GR28, in register FR4, or in a temporary storage area provided by the caller.
If the result is returned in a temporary storage area, the calling procedure provides the temporary area and passes its address in GR28.
On Intel x86 systems, the result of a function is returned in one of the following three ways, depending upon the result's data type and if the floating-point coprocessor is used:
A function procedure returns its result value to the calling procedure in one of three ways, depending upon the data type:
If the result is returned in a temporary storage area, the calling procedure provides the temporary area and passes its address as the first (hidden) parameter in the call.
On the Sun Sparc, the result of a function is returned in one of the following four ways, depending upon the result's data type:
On Sun Sparc systems, the calling procedure provides the temporary area and stores the address to the temporary area in the one-word hidden parameter of the user frame at %sp+0x40 prior to the call.
Table 2-3 lists the Open PL/I data types and the registers to which they are returned on each platform.
| Open PL/I Data Type | Register Returned in | |||
|---|---|---|---|---|
| HP | Intel | RS/6000 | Sun Sparc | |
| Fixed Binary
Character(1), not * or Varying Bit(1), not * Pointer Offset File | GR28 | eax | GPR3 | o0 |
| Float Binary | FR4 | on top of the floating-point coprocessor stack | FPR1 | f0/f1 |
| Fixed Decimal
Float Decimal Character(n), n > 1 or n = * Character(n) Varying Bit(n), n > 1 or n = * Picture Label Entry | Returned in Temporary Storage Area | |||
Table 2-4 lists compatible data types for determining equivalent argument type correspondence. Some data types (for example, char in C) are used more than once in the table to show the correspondence of equivalent types in more than two languages. The subscripts used in the table have the following meanings:
| PL/I | ||||||
|---|---|---|---|---|---|---|
| COBOL | C | C++ | FORTRAN | BASIC | PASCAL | |
| Fixed Bin, P <= 7 | COMP PIC
S9 (1) – S9 (2) |
char | char | INTEGER*1 | – | – |
| Fixed Bin,
8 <= P <= 15 |
COMP PIC
S 9 (3) – S 9 (4) |
short | short | INTEGER*2 | INTEGER (%) | Integer |
| Fixed Bin, P >15 | COMP PIC
S 9 (5) – S 9 (9) |
int or long | int or long | INTEGER*4 | – | Integer |
| – | – | char | char | INTEGER*1 | – | Packed Array[1...5] |
| Character (n) | DISPLAY A(n) or PIC X(n) | char [n] | char[n] | CHARACTER*n | – | – |
| Character (N) Varying | DISPLAY PIC X OCCURS num1 to num2
DEPENDING on N |
struct
{short s; char c[n];} |
struct
{short s; char c[n];} |
– | – | Char |
| Character (1) | DISPLAY PIC X | char | char | CHARACTER*1 | – | – |
| Character (*) | – | char[ ] | char[ ] | – | – | – |
| Fixed Decimal | COMP–3 PIC S9 (n) | – | – | – | – | – |
| DISPLAY PIC S9(n) SIGN TRAILING | – | – | – | – | – | |
| – | DISPLAY PIC S9(n) SIGN LEADING SEPARATE | – | – | – | – | – |
| – | DISPLAY PIC S9(n) SIGN TRAILING SEPARATE | – | – | – | – | – |
| Bit(1) | – | – | – | – | – | – |
| Bit(1) Aligned | – | char | char | – | – | Boolean |
| Bit(N) Aligned | COMP–5 PIC
[S] 9 (n), n<5 |
– | – | – | – | Set |
| – | – | int or long | int or long | LOGICAL*4 | – | – |
| – | – | short | short | LOGICAL*2 | – | – |
| – | – | char | char | LOGICAL*1 /BYTE | – | – |
| Float Bin, p > 23 | COMP–2 | double | double | REAL*8 | REAL (#) (MBASIC) | – |
| Float Bin, p <= 22 | COMP–1 | float | float | REAL*4 | REAL (1) (MBASIC) | Real |
| – | – | struct
{float real, imaginary;} |
struct
{float real, imaginary;} |
COMPLEX*8 | – | – |
| – | – | struct
{double real; double imaginary} |
#include <complex.h> class complex | COMPLEX*16 | – | – |
| Pointer | – | Pointer | Pointer | – | – | Pointer |
| Label | – | – | – | alternate return | – | – |
| Entry | DISPLAY PIC X(32) | – | – | Dummy procedure | – | – |
| Float Decimal | – | – | – | – | REAL (CBASIC) | – |
| – | – | – | – | – | STRING
($) |
– |
| Area | – | – | – | – | – | – |
| Offset | COMP PIC
S 9 (5) – S 9 (9) |
int or long | int or long | INTEGER*4 | – | integer |
Copyright © 2009 Micro Focus (IP) Ltd. All rights reserved.