![]() |
Iron Spring PL/I CompilerProgramming Guide
|
This is beta software. Some PL/I features are still missing from this version. A partial list is provided under restrictions below. |
PL/I is widely used on mainframes and midrange systems today, but since the demise of Digital Research, Inc. has not been easily available on personal computers.
This is the second beta version of Iron Spring PL/I. Version 0.8c is still missing some features of full PL/I, but their addition should not affect features already working. The section Restrictions lists many of the missing features.
Modifications to Guide for 0.8c
Modifications to Guide for 0.7a
Modifications to Guide for 0.6a
Trademarks
eComStation is a trademark of Serenity Systems International.
EMX is a trademark of Eberhard Mattes.
Gnu is a trademark of the Free Software Foundation.
IBM is a trademark of IBM, Inc.
Intel is a trademark of Intel Corporation.
Iron Spring is a trademark of Iron Spring Software.
Linux is a registered trademark of Linus Torvalds.
VAX is a trademark of Hewlett-Packard, Inc.
WATCOM is a trademark of Sybase, Inc. and its subsidiaries.
The compiler doesn't yet support building Presentation Manager
applications. Only text-mode applications are allowed.
PL/I procedures can call functions coded in other languages as
long as they use the "SYSTEM" calling convention. The "OPTLINK"
and other calling conventions are not supported.
Programs in other languages can call PL/I procedures with restrictions.
The main program must be PL/I.
See Program Linkage for more information.
Major features not implemented
Other features
Restrictions
This is a list of major current restrictions of the compiler.
All other preprocessor statements will generate a diagnostic.
See Preprocessor for more information.
The COPY option of the GET statement, the ONKEY and SAMEKEY builtin functions.
ACOS ASIN ATAN ATAND ATANH COSH SINH TANH ERF ERFC EXP
CONJG ROUND TRUNC
The compiler error message 995 ("Unimplemented feature xxx") and the
run-time condition "UNIMPLEMENTED" are used to flag unimplemented
features. Except for "permanent restrictions" noted above,
these should be removed in future releases. Some infrequently-used
conversions may be only partially implemented.
Compiler Limits | |
---|---|
Maximum number of dimensions | 15 |
Maximum number of levels in a structure | 15 |
Maximum level number in a structure | 255 |
Maximum number of picture characters in a picture (after expanding all repetition factors) | 511 |
Maximum length of a CHAR or BIT string (after expanding all repetition factors) | ~32000 |
Maximum nesting depth of %INCLUDE files | 4 |
Maximum precision of FIXED DECIMAL data | 18 |
Default precision of FIXED DECIMAL data | 5 |
Maximum precision of FIXED BINARY data | 31 |
Default precision of FIXED BINARY data | 15 |
Maximum precision of FLOAT DECIMAL data | 20 |
Default precision of FLOAT DECIMAL data | 6 |
Maximum precision of FLOAT BINARY data | 64 |
Default precision of FLOAT BINARY data | 52 |
Minimum/maximum scale factor | -128 / 128 |
Maximum length of an internal or external label | 31 |
See Restrictions for information on major language features that are not currently implemented.
The syntax of the PLIC command is shown. The case of the option switches is significant. Lower-case options have parameters, upper-case do not.
PLIC [<options>] <input files> [-o <output file>] <options> = <output option> [<include options>] [<listing options>] [<source margins>] [<character substitutions>] [<version info>] [<error option>] [<misc options>] (options may be entered in any order). <output option> = -S | -C | -L -S = generate assembler (symbolic) output. -C = generate compiled (object) output. -L = generated linked (EXE or DLL) output. (this option not currently implemented.} <include options> = -i<directory> where <directory> is the absolute or relative path to a directory to be searched for %INCLUDE files. This option may be used more than once on the command line, and directories will be searched in the order listed. <listing options> = -l[siaxgm] one or more of [siaxgm] may be entered, in any order. -ls = list source -li = list insource -la = list attributes -lx = list cross-reference -lg = list aggregates -lm = list generated code in a format similar to an assembly listing. Currently, the insource and aggregate listings are not available. <source margins> = -m(start[,end]) This option defines the first and last positions of each input line that contain input for the compiler. If this option is omitted the source is assumed to be the entire line. This is included for compatibility with mainframe compilers which would use, for example, -m(2,72). <character substitutions> = -cn(<list>) and/or -co(<list>) This option defines up to four characters each to be used as substitutions for the NOT(¬) [-cn()] and/or OR(|) [-co()] operator IN ADDITION TO the defaults. The caret (^) is a metacharacter for the OS/2 command processor; if the caret is to be used, code two consecutive carets, for example -cn(^^). <version info> = -V The compiler prints version and copyright information on stderr. <error option> = -e<option> This option sets the errorlevel returned by the compiler for warning and error messages. Normally compiler returns 4 if only warnings were issued, and 8 for any errors. -ew tells the compiler to return 0 if only warning messages were issued. -es tells the compiler to return 0 if any errors or warnings were issued. This option is useful when the compiler is run from a script or makefile. <misc options> = -d<option> <option> is a character string, with or without enclosing quotes. -dLIB tells the compiler it is compiling a standard run-time library procedure. -dELF causes the compiler to generate ELF object files. -dOMF causes the compiler to generate OMF object files. The default is to generate the standard object format for the host OS; for OS/2 -dOMF is the default. <input files> and <output files> are absolute or relative path names. Only one input and one one output file are currently allowed. If the output file is omitted the name is generated. For example, PLIC -S abc.pli will create a file named abc.asm.
declare two_line_constant char(24) static initial( ('Line one' || '0D0A'x || 'Line two.') );This type of expression is resolved at compile-time and does not generate any additional code.
The default representations for the OR and NOT characters are '|' and '¬' (U+004F and U+00AA respectively. 'AA'x is ALT-1-7-0 on the numeric keypad.) As indicated above under Running the compiler, the options -cn and -co can be used to indicate additional encodings used to represent these characters.
String data can be delimited by either the single (') or double (") quote characters. The same character must be used to begin and end the string. The character not used as a delimiter may be part of the string. If portability is a concern, use only the single-quote to delimit strings. The character used as a delimiter can be included in the string by specifying it twice in succession, for example, 'Let''s dance' will be compiled as Let's dance, """Fine"", he said" as "Fine", he said.
Source lines are logically continued from the right margin of one line to the left margin of the next, with no whitespace assumed between the two character positions. (see the -m compiler option). Any characters outside the margins, as well as any characters lower than space in the collating sequence, are ignored. For example:
Left Margin Right Margin Line End | | | "This is a continued charsome stuff outside the margin extra stuff acter string"will be compiled as This is a continued character string.
If a line ends with a statement keyword with no trailing blank, and another keyword begins in the left margin of the next line the two keywords will be considered a single keyword token. A future release will cause words and numbers, but not strings, operators, etc., to break at the end of a line.
INCLUDE files are identical in format to the source file. Currently INCLUDE files must have either no extension or the extension ".inc" or ".cpy". The compiler option -i, which can be repeated multiple times, provides a list of directories to be searched, in the order written, to locate an INCLUDE file. The current working directory is always searched last if the file is not found sooner. INCLUDE files use the same list of alternate characters as the source, and must use the same margins, although a future release will allow these to be overridden for each individual file.
Source listing:
'B' is the line number. The source file and each %include file
are numbered starting from line one. A future compiler version will also provide a file
number for each include file to be used on error messages.
'C', the next 100 characters of the listing, show the input line.
If the line is longer than 100 characters additional unnumbered lines will display the overflow.
The line following line 342 above shows the format of error, warning, and information messages.
'D' is the source line number.
'E' is the severity and message number (xxxyyy)
'xxx' is 'INF' for information-only messages as shown,
'WRN' for warnings, and 'ERR' for errors. 'yyy' is a unique message identifier for this error.
'F' is the message text.
Currently messages generated by the parser appear intermixed in the source listing, while code
generator messages appear at the end of the source, or intermixed in the object code listing if
one is produced. In a future version all messages will appear at the end.
The listing is paginated with imbedded formfeed characters 'G',
currently every fifty-six lines.
Attribute and cross-reference listings:
'J' lists the data attributes, which should be self-explanatory.
This field may occupy more than one line.
'K' shows the address of the item in < >. The addresses are displayed as follows:
Assembler listing: Here is a small sample of the object code listing:
If there were any errors or warnings, a message showing the number of them appears at the end
of the listing.
Object output:
If the compiler option "-ls" is specified, compiling a program xxx.pli will create a source listing file named xxx.lst.
Here are a few lines from a listing: The letters in blue are a key to the descriptions below, and are not part of the listing.
A B C
340
341 %include DSA;
342
D E F
341 (INF104)Processing include file DSA.
G
1 /********************************************************************/
2 /* */
If the compiler options "-la' and/or "-lx" are specified, the attribute list (symbol table) and/or
cross-refreence listing is printed as shown below.
Variables are listed in alphabetic order. The variable names always appear, "-la" causes the variable
attributes to be printed, "-lx" causes the cross-reference listing to be generated. The example below
shows the results of specifying "-lax".
H I J K
ADDR 124 Builtin
BSW 309 Entry Unaligned < Code+'13C0'x >
265
BYTE 332* Builtin
737 738
C 77 Char(1) Unaligned < DSA-'51'x(1) >
266 278 300 321 346 362 370 446 452 453
478 507 510 512 514 516 531 553 557 566
C4 109 Char(4) Unaligned Based < +'00'x(4) >
297 298 533 615 679
C4 327 Char(4) Unaligned Parameter < Loc @DSA+'08'x(4) >
723 724 725 726 727
CONDS 97 (9) Char(6) Var Unaligned Static Init() < Static+'12'x(8) >
407 635
DSA_BELOW_EBP 27 Unaligned Structure In(PLI_DSA) < +'00'x(32) >
635 636 642 643 644 646 647
DSA_CHC 33 Ptr Aligned In(PLI_DSA.DSA_BELOW_EBP) < +'08'x(4) >
643
PLI_DSA 340 Unaligned Based Structure Level(1) < +'00'x(40) >
'H' is the name of the data element.
If the name is longer than twenty characters it will appear
on a line by itself, with the remaining data shown on the next line.
'I' is the line
number of the declaration of this item. Undeclared data, like 'BYTE' above show the line number where this
element is first used, followed by '*'.
If the -lm option was specified, a listing of the generated code will appear between the source listing
and the attribute list. This is similar in format to the listing generated by ALP. The major difference
is that ALP displays immediate operands in big-endian order. This listing will always display immediate
operands as they are stored in memory, i.e. little-endian.
; Stmt 2, Line 3 (PUT)
.code
00000025 83 EC 40 sub esp,64
00000028 66:C7 04/24 0100 mov word ptr 0[esp],1
0000002E 89 6C/24 [0C] mov dword ptr 12[esp],ebp
00000032 C7 44/24 [10] 00000000 mov dword ptr 16[esp],0
0000003A 0F BF 75 [E6] movsx esi,word ptr -26[ebp]
0000003E 66:89 74/24 [2C] mov word ptr 44[esp],si
00000043 66:C7 44/24 [02] 1500 mov word ptr 2[esp],21
0000004A C7 44/24 [04] 00000000:R mov dword ptr 4[esp],offset _SYSPRINT
00000052 C7 44/24 [08] 04000000:R mov dword ptr 8[esp],offset _pli_data+04h
0000005A C7 44/24 [14] C0001000 mov dword ptr 20[esp],001000C0h
extern _pli_Put:near
Compiling a program xxx.pli with the -C option will create an object file xxx.obj.
The program contains a single code segment 'CODE32', a single static data segment 'DATA32', and zero or more
external data segments as described under Assembler output. No BSS segment or
symbolic debug information is generated.
Internal Data Representations | |
---|---|
FIXED BIN, precision 7 or less | BYTE |
FIXED BIN, precision 15 or less | WORD |
FIXED BIN, precision 31 or less | DWORD |
FIXED DEC, any precision Intel x87 BCD format | TBYTE |
FLOAT BIN, precision 23 or less Intel x87 short floating-point | REAL4 |
FLOAT BIN, precision 52 or less Intel x87 long floating-point | REAL8 |
FLOAT BIN, precision>52 Intel x87 extended floating-point | REAL10 |
FLOAT DEC, precision 5 or less | REAL4 |
FLOAT DEC, precision 14 or less | REAL8 |
FLOAT DEC, precision>14 | REAL10 |
CHARACTER(n) | n bytes |
BIT(n) ALIGNED | (n+7)/8 bytes |
BIT(n) UNALIGNED | n bits |
PTR, OFFSET | NEAR PTR |
Work file:
The compiler creates a temporary work file named PLI-xxxxxxxx-yyyyyyyy-zzzzzzzz.tmp
in the current working directory. Normally this file is deleted at the end
of compliation. Errors in the beta version of the compiler causing
certain traps may prevent automatic deletion of this file.
If it not automatically removed it may be deleted manually.
Iron Spring PL/I can read and write:
File Declarations
The general form of a file declaration is shown below. As usual, keywords can be specified in any order. Many
keywords may be specified either in the declaration or in the OPEN statement for the file. If they are
specified in both, they must not conflict. For example, a file declared INPUT cannot be opened as OUTPUT.
>>-DECLARE-name-+------+-+--------+-+--------+-+----------------------------------+-+------------------+-><
| | | | | | | | | |
+-FILE-+ +-RECORD-+ +-INPUT -+ +-ENVIRONMENT(environment options)-+ +-other attributes-+
| | | |
+-STREAM-+ +-OUTPUT-+
| |
+-UPDATE-+
RECORD and STREAM Files
INPUT, OUTPUT, and UPDATE
SYSIN | ENV(V CRLF RECSIZE(120)) LINESIZE(120) |
SYSPRINT | ENV(V CRLF RECSIZE(120)) LINESIZE(120) PAGESIZE(60) |
If stdin and stdout are the current VIO window, these files default to ENV( BLKSIZE(0) ). |
Data Specification
SKIP[(expr)]Input/Output Statements
OPEN and CLOSE apply to both STREAM and RECORD files. The GET and PUT
statements operate on STREAM files. The READ, WRITE, REWRITE, and LOCATE
statements operate on RECORD files. The assumption is made that the reader is familiar with, or has access
to a reference for, the I/O statements of IBM PL/I for MVS and VM. Only the syntax accepted by Iron Spring
PL/I is shown here, no explanation is provided.
+----------------------- , -------------------------------------+
v |
>>-OPEN--.---FILE(file_ref)-+------------------+----+---------------+----+---- ; ----><
| | | |
+-|stream-options|-+ +-TITLE(string)-+
| |
+-|record-options|-+
|stream-options|
+-INPUT ---------------------------+
| |
|----STREAM---+----------------------------------+-+-------------+-----|
| | | |
+OUTPUT ---+-----------------------+ +-LINESIZE(m)-+
| |
+-PRINT-+-------------+-+
| |
+-PAGESIZE(n)-+
|record-options|
+-INPUT -+
| |
|---RECORD----+--------+-+------------+-+-------+------|
| | | | | |
+-OUTPUT-+ +-BUFFERED---+ +-KEYED-+
| | | |
+-UPDATE-+ +-UNBUFFERED-+
STREAM Input/Output
>>-GET-FILE(file_ref)-+-----------------+-+----------------------+- ; --><
| | | |
+-SKIP----------+-+ +-|data_specification|-+
| |
+-(expr)-+
>>-PUT-FILE(file_ref)-+---------------------+-+----------------------+- ; --><
| | | |
+-PAGE-+------------+-+ +-|data_specification|-+
| | | |
| +-LINE(expr)-+ |
| |
+-SKIP-+--------+-----+
| | | |
| +-(expr)-+ |
| |
+-LINE(expr)----------+
|--+------+---( |data-list| )---------------------+----|
| | |
+-LIST-+ |
| |
+-DATA---+-----------------+-------------------+
| | | |
| +-( |data-list| )-+ |
| |
| +-----------------------------------+ |
| v | |
+-EDIT---.-( |data-list| )-( |format-list| }-+-+
The SKIP option causes a new line to be started
in the data stream prior to transmitting any data from the current or subsequent GET or PUT statement.
The (expr) is converted to an integer n. On output, n newlines (linefeed or
carriage-return/linefeed) are inserted. On input the remainder of the current line and the n-1 following
lines are skipped.
If (expr) is omitted or not greater than zero, 1 is used for the value of n.
For PRINT files, the ENDPAGE condition may be raised if PAGESIZE is exceeded.
>>-DISPLAY (expression)--+-----------------+--+-------------------+----------- ; -->< | | | | +-REPLY(char-ref)-+ +-EVENT(event-ref)--+"expression" is converted to a character string and written to stderr. If the "reply" option is not specified, this is followed by a newline. Otherwise the "reply" and "event" options are currently ignored.
ALLOCATE(n) | ALLOCATE allocates n bytes of storage and returns a pointer to the first byte. [OS2][ENT] |
BYTE(n) | BYTE returns a character string of length one equivalent to the
following: SUBSTR( COLLATE(), MOD(n,256)+1, 1 ) [ENT][VAX] |
COLLATE | COLLATE Returns a character string of length 256 containing all 256 possible character values. [OS2][ENT][VAX] |
COMPARE(x,y,z) | COMPARE compares "z" bytes at locations pointed to by "x" and "y". [OS2][ENT] |
COPY(x,y) | COPY returns a string consisting of "y" concatenated copies of string "x". [OS2][ENT][VAX] |
HEXIMAGE(x,y[,z]) | HEXIMAGE returns a character string that is the hexadecimal representation of 'y' bytes of storage at location 'x'. If 'z' is omitted, the length of the returned string is 2*y. If 'z' is present it must be CHARACTER(1) nonvarying, and the value of 'z' is inserted between every set of eight characters in the output string. In this case the length of the returned string is (2*y) + floor((y-1)/4). [OS2][ENT] |
PLIFILL(x,y,z) | PLIFILL moves "z" copies of a single byte "y" to a location "x" with no conversion, padding, or truncation. [OS2][ENT] |
PLIFREE(p) | PLIFREE frees storage at location "p" allocated by the ALLOCATE builtin. [OS2][ENT] |
PLIMOVE(x,y,z) | PLIMOVE moves "z" bytes to the location pointed to by "x" from the location pointed to by "y". [OS2][ENT] |
RANK(c) | RANK returns a FIXED BINARY(15) result. "c" is a
character string of length one. RANK(c) is equivalent to the following: INDEX( COLLATE(), c ) - 1 [ENT][VAX] |
STRING(x) | STRING concatenates the elements of array or structure "x" and returns the result. "x" is any reference that is suitable for string-overlay defining. Bit strings should have no gaps between elements caused by alignment. The string returned is a nonvarying character or bit string depending on the type of "x". The length of the string is the total number of characters or bits in "x". [ENT][VAX] |
PROCEDURE-+--------------------+-+-----------------+-+-----------------+-+-------------+-+------------------+-- ; >< | | | | | | | | | | +-| ( parameters ) |-+ +-| returns-opt |-+ +-| options-opt |-+ +- RECURSIVE -+ +-| external-opt |-+
ENTRY--+--------------------+-+-----------------+-+-----------------+-+-------------+-+------------------+- ; >< | | | | | | | | | | +-| ( parameters ) |-+ +-| returns-opt |-+ +-| options-opt |-+ +- RECURSIVE -+ +-| external-opt |-+
|parameters| +------- , ----------------+ v | |-.- parameter-description --+----|Each parameter-description supplies the attributes for one parameter, therefore the entry expects as many arguments as there are items in the list. A parameter-description is a list of data attributes that describes that parameter. For example: FIXED BINARY(7), CHARACTER(8), POINTER, or ENTRY would all be valid parameter descriptions.
|returns-opt| |-- RETURNS ( returns-description ) ---|The returns-description describes the attributes of the data which will be returned by this entry if it is invoked as a function. If the returns-opt is omitted the attributes are determined by the first character name of the first or only name prefix: I-N=FIXED BINARY(15), other=FLOAT DECIMAL(6).
|options-opt| +--- , --------+ | | +--------------+ v | |---- OPTIONS ( . entry-option + ) ---|Each entry-option is one of the following:
LINKAGE(OPTLINK) will be implemented in a future version to specify the "Optlink" calling convention that uses registers for some arguments.
RECURSIVE is supported for compatibility only. It indicates that this entry may call itself, either directly or indirectly through a chain of calls. Iron Spring PL/I assumes all entries are potentially recursive.
|external-opt| |-- EXTERNAL --+----------------------+---| | | +- ( external-name ) --+The external-name is a character string, enclosed in quotes, representing the name by which this entry will be known to external callers. External 'external-name's beginning with the string "_pli" are reserved for use by the run-time library. If the 'external-name' is not specified, the default external name is an uppercase translation of the first label on the external procedure or entry name. For example, x: y: PROCEDURE; will use "X" as the external name for the linker.
DECLARE-- decl-name --ENTRY-+--------------------+-+-----------------+-+-----------------+-+------------------+-- ; >< | | | | | | | | +-| ( parameters ) |-+ +-| returns-opt |-+ +-| options-opt |-+ +-| external-opt |-+Parameters, returns-opt, and external-opt are described under "PROCEDURE and ENTRY Statements" above.
|options-opt| +--- , --------+ | | +--------------+ v | |---- OPTIONS ( . entry-option + ) ---|The following options are valid for entry declarations:
For OS/2 system exceptions, "hhhhhhhh" and "tttttttt" are the hexadecimal value and the description of the exception respectively.
The sample program 'numwrd.pli' is an example of a program that uses the command-line.
PL/I programs use the stack for activation records for procedures and BEGIN-blocks, including all AUTOMATIC storage. The heap is used for all allocated BASED and CONTROLLED storage, for control information for error-handling, and for file information and buffers.
The stack size is taken from the value stored with the executable, either by the linker, by EXEHDR, or a default minimal value of 16K bytes. Stack storage is allocated when the program is loaded, but is not committed until actually used. Stack probes are employed to prevent traps when more than 4K is requested at one time.
The heap size is currently fixed at 1MB (1024K), although a future release will allow this value to be respecified at run time. In the interim, if a larger heap is required, the library procedure INIT can be re-assembled specifying a larger value for the data item 'def_heap_size'.
The layout of the stack frame for one procedure or Begin-block is illustrated below.
^ | | | +08 | Parameters (see program linkage below) | Higher addresses +------------------------------------------+ | +04 | Calling program's EIP | | +------------------------------------------+ | EBP+00 | Calling program's EBP | | +------------------------------------------+ | | PL/I control information | | | [see library include file 'dsa.inc' | | | for layout (subject to change)] | | | ... | v +------------------------------------------+ Lower addreses | AUTOMATIC non-adjustable data | | for this block | | ... | +------------------------------------------+ | AUTOMATIC adjustable data | | ... | +------------------------------------------+ | Temporaries, argument lists | ...
For both conventions, the called program is responsible for saving registers EBP, and EBX, ESI, and EDI. It is the caller's responsibility to save any other registers used. If the called entry is specified with OPTIONS(ASM), the caller saves and restores the 80x87 FPU control register. The calling program passes the size of the argument list in DWORDs in AL.
The standard PL/I calling sequence passes all arguments by reference, that is by passing their addresses and, optionally, the addresses of their descriptors. This means that changes to the values of parameters in the called procedure are reflected back to the caller. Descriptors are passed for structure, array, and string arguments. Normally descriptors are not passed for arithmetic arguments, although many PL/I runtime procedures require a descriptor. The library include file 'desc.inc' shows the layout of descriptors for various types of data [subject to change in future releases]. When the argument is a constant, an expression, or the data type doesn't match the corresponding parameter, a dummy argument is created and placed on the stack; the called procedure is passed the address of the dummy. In this case, changes to the values of parameters change the dummy argument and don't modify the actual argument.
The "SYSTEM" calling sequence passes arguments by value. All arguments, normally limited to arithmetic data, pointers, and nonvarying strings, are evaluated and the values are passed to the called procedure; descriptors are not used. Changes to the values of parameters do not cause changes in the values of the corresponding arguments.
Descriptors for non-adjustable data are normally stored in STATIC storage, descriptors for adjustable data are created during block initialization and stored in the current stack frame.
Two other pieces of information are also passed to a called PL/I procedure. The static backchain is passed in ESI, and the address of the Program Global Table (PGT) is passed in EDI. These are passed for both "system" and PL/I linkage unless the called entry is specified with OPTIONS(ASM). The PGT is a vector table containing the addresses of some required runtime routines. The static backchain is the EBP value of the block which lexically contains the called procedure. This allows the called procedure to reference automatic data belonging to containing blocks. This is not necessarily the same as the EBP value of the caller. For example, consider the following:
A: PROC; CALL B; B: PROC; CALL B; C: BEGIN; END; END B; END A;A is always the 'containing' block of B, regardless of whether B is called from A or from itself recursively. B is the containing block of block C. Using the static backchain, C can address AUTOMATIC data from B and A, and so on.
The stack layout for a standard PL/I call is illustrated below.
+--------------//--------------------------+ | Space for returned value | +------------------------------------------+ <--------+ | (optional, locator/ +------------------------------------------+ | descriptor pair | Address of descriptor | ---> | for returned value) +------------------------------------------+ | | Address of data | ---------+ +------------------------------------------+ (optional) +-------------//---------------------------+ | Dummy arguments | | ... | +------------------------------------------+ (optional, locator/ +------------------------------------------+ descriptor pair | Address of descriptor | ---> for arguments +------------------------------------------+ requiring a | Address of data | ---> descriptor - +------------------------------------------+ <------+ one per argument) | | (optional) +-------------//---------------------------+ | | Saved values of 'live' registers | | | not saved by the called procedure | | | ... | | +------------------------------------------+ | | +------------------------------------------+ | | Argument list, one address per argument. | | | This address points to either the data | | | or the address of the locator/ | -------+ | descriptor pair for the data. | | The last (highest addressed) argument | -or- | identifies the returned value. | -------> argument ESP -----> +------------------------------------------+
EXTERNAL data (not EXTERNAL ENTRY) is not shared between executable and DLL code, nor among procedures in different DLLs. For example, data declared DECLARE a EXTERNAL POINTER; will identify different "a"s in procedures linked into in the executable, in DLL "1", and DLL "2". Within the executable or any one of the DLLs all occurrences of that declaration will identify the same "a". Each level-1 external data declaration generates a segment for the linker.
Oncode Condition Value finish 4 error 9 name 10 record 20 transmit 40 key 50 endfile 70 undefinedfile 80 endpage 90 pending 100 stringsize 150 overflow 300 fixedoverflow 310 zerodivide 320 underflow 330 size 340 stringrange 350 area 360 attention 400 condition 500 check 510 subscriptrange 520 conversion 600
%INCLUDE: | The %INCLUDE statement instructs the compiler to read an external file of text and insert its
contents in place of the %INCLUDE. The syntax is: "%INCLUDE <filespec>;". <filespec> is any valid OS/2 file specification. If no file extension is coded the compiler will search for files having the extensions ".cpy", ".inc", or no extension. The search path for the file is specified on the PLIC command (see Running the compiler). Examples of the %INCLUDE statement are: %INCLUDE ABC; [will include "ABC", "ABC.CPY", or "ABC.INC" in your search path] %INCLUDE "def.pli"; [will include "DEF.PLI" in your search path] %INCLUDE "c:\pli\includes\ghi.pl1"; [will include the named file only] Nested includes are allowed, that is, the included file may itself contain %INCLUDE statements. The maximum depth of nesting is four levels.
|
%REPLACE: | The %REPLACE preprocessor statement provides limited text substitution
capability. The syntax is "%REPLACE <identifier> BY <constant>;". <identifier> is any word which would be valid as an identifier in a PL/I program. PL/I keywords are not allowed. Multiple %REPLACE statements may specify the same identifier, with the most recently-occurring one being in effect. <constant> is any valid character-string, bit-string, or arithmetic constant. The scope of the %REPLACE statement is between its occurrence in the input stream to the end of the source program, including any included files. The effect is to substitute the value of <constant> in the program anywhere <identifier> appears. For example, the following sequence of statements: %REPLACE abc by 1; put edit(3+abc)(f(5));will result in the value 4 being output by the PUT statement. The %REPLACE statement above is equivalent to the following, but does not require a full preprocessor scan: %DECLARE abc CHARACTER; %abc = '1';
|
%PRINT: | The %PRINT statement turns on (enables) printing of the source listing. The %PRINT statement itself will not be printed if the listing was previously disabled. |
%NOPRINT: | The %NOPRINT statement turns off (disables) printing of the source listing. The %NOPRINT statement itself will be printed if the listing was previously enabled. |
%PAGE: | The %PAGE statement causes a page eject in the source listing after printing of the %PAGE statement, if the listing is enabled. |
%SKIP: | The %SKIP[(n)] statement will print 'n' blank lines (n=1 to 9) in the source listing following the printing of the %SKIP statement, if the listing is enabled. If 'n' is omitted, the default is one line. |
PUT LIST(a); PUT LIST(b);use:
PUT LIST(a,b);
DECLARE osdelete ENTRY( CHAR(*) VAR ) RETURNS( FIXED BIN(31) ) EXT( '_pli_OSDelete' ); DECLARE rc FIXED BIN(31); RC = osdelete( filename );
tempnam generates a unique name for a temporary file.
The following steps are not required, but will simplify debugging.
To get the debugger to stop at the beginning of the PL/I program,
make the following modifications to "setup.dbg", normally found
in the <WATCOM>\binw directory.
DECLARE tempnam ENTRY( CHAR(*) VAR, CHAR(*) VAR, CHAR(*) VAR )
RETURNS( CHAR(260) VARYING)
EXT( '_pli_Tempnam' );
DECLARE temp_filename CHAR(260) VARYING;
temp_filename = tempnam( sDir, sPfx, sSfx );
'sPfxpppppppp-tttttttt-uuuuuuuusSfx'
where 'pppppppp' is the hex value of the current process id (pid),
'tttttttt' is the hex value of the current thread id (tid), and 'uuuuuuuu'
is a unique number within this process. If another file with this name
already exists, the unique number is incremented until the generated name
does not confilct with an existing file.
Debugging PL/I programs
Debuggers
The WATCOM® debugger may be used to debug PL/I programs.
Source-level debugging is not yet available, but since the
compiler can generate assembly-language output, debugging
at the assembly level is straightforward.
elseif _dbg@dbg$os == 12 && ?@main { | Following this |
go/until/noflip @main | |
} | |
elseif ?@@_PLI_MAIN { | Insert these three lines |
go/until/noflip @@_PLI_MAIN | |
} |
The IBM "ASDT" debugger is also usable.
Sometimes it may be desirable to compile-in a breakpoint to be activated when a specific location is reached or condition occurs. The following statement inserted in your source will activate a breakpoint when it is reached when running under control of a debugger:
*PROCESS DBG(INT3);If the resulting executable is not run under a debugger, the interrupt will be ignored. Nevertheless, INT3 traps should not be left in a production program.
Future versions will be extended to dump PL/I STATIC storage ('H'), and information about opened files ('F').
Options may be combined and may appear in any order, for example "TCB" means: print trace, continue after snap, and dump all automatic storage.
The stack is dumped from the current procedure (_pli_Dump) [lowest address] to the PL/I startup code (_pli_Init) [highest address]. Storage for each procedure is dumped in three sections (see sample segment of PLIDUMP output below): Temporaries (argument lists and storage used during expression evaluation), Data (AUTOMATIC variables and other non-temporary user data in the stack frame), and DSA (system data in stack frame). The layout of the DSA is given in lib\include\dsa.inc. This is subject to change in future releases.
If the dump is issued as result of an OS/2 system exception, trap information will appear immmediately before the DSA of the procedure in which the exception occurred.
Each data line includes the actual address of the first byte, the offset (±EBP for DSA and data, +ESP for temporaries), up to sixteen bytes of data in hex as actually stored in memory (no byte-swapping), and the ASCII representation of the same data.
The DSA display provides additional formatted information regarding the ON-conditions enabled for this block and identifies runtime-library procedures.
***error dump*** Address Caller Entry name ... omitted from the example ... OS/2 System Trap Information System Code=C0000005 XCPT_ACCESS_VIOLATION Exception Address=000100D7 EAX 44000B00 EBX 00020000 ECX 00000000 EDX 44000B00 ESI 00000000 EDI F8070200 DS 0053 ES 0053 FS 150B GS 0000 CS:EIP 005B:000100D7 SS:ESP 0053:00048600 EBP 00048628 EFLAGS 00012216 0001868A 00027402 FTPRO Temporaries at 003C80C4 003C80C4 ( 000000) 74823C00 5C863C00 98823C00 3C813C00 |t.<.\.<...<.<.<.| 003C80D4 ( 000010) 53003C00 F4803C00 5C863C00 A8A2021C |S.<...<.\.<.....| ... omitted from the example ... 003C83B4 ( 0002F0) 3C843C00 00000000 3C843C00 C4833C00 |<.<.....<.<...<.| 003C83C4 ( 000300) 64140500 |d...| Data at 003C83C8 003C83C8 (-000074) 786D0500 00843C00 3E350400 E4C34300 |xm....<.>5....C.| 003C83D8 (-000064) 00000000 30823C00 0083E180 B8813C00 |....0.<.......<.| 003C83E8 (-000054) 0000E181 E4C34300 00000000 B5570400 |......C......W..| 003C83F8 (-000044) 31000000 10843C00 786D0500 80853C00 |1.....<.xm....<.| 003C8408 (-000034) 12720200 600F3C00 01001500 00001B00 |.r..`.<.........| 003C8418 (-000024) E0320500 |.2..| DSA at 003C841C Enabled: CONV FOFL OFL UFL ZDIV 003C841C (-000020) C8833C00 0000E180 E4C34300 00000000 |..<.......C.....| 003C842C (-000010) 8A860100 31000000 48843C00 786D0500 |....1...H.<.xm..| 003C843C ( 000000) 80853C00 02740200 |..<..t..| 00026C79 00010123 PH10 Temporaries at 003C8444 003C8444 ( 000000) 48843C00 11000000 42000000 |H.<.....B...| ... omitted from the example ...