PL/I preprocessor: Difference between revisions

Content deleted Content added
Preprocessor builtins
Evolution: %THEN and %ELSE
 
(44 intermediate revisions by 18 users not shown)
Line 1:
{{nomore footnotes|date=February 2012}}
The '''PL/I preprocessor''' is the [[preprocessor]] for the [[PL/I]] computer [[programming language]]. The preprocessor interprets a subset of the full PL/I language to perform [[source file]] inclusion, [[conditional compilation]], and [[Macro (computer science)|macro expansion]].
 
The preprocessor language has a PL/I-like syntax with preprocessor statements and preprocessor procedures prefixed with a [[percent sign|percent symbol]] (<code>%</code>). Listing-control statements, which supply formatting commands for the [[compiler]] listing, are usually considered preprocessor statements and also begin with '<code>%'</code>. Preprocessor statements are imbedded in and operate on input text. The input text is normally a PL/I program, but is agnostic to the grammar of PL/I, so the preprocessor can also be used independently to process other kinds of text files.
 
The preprocessor is not specified as part of standard PL/I, but most PL/I implementations accept the language of the IBM preprocessor.
Line 8:
==Including files==
 
The '''<code>%INCLUDE'''</code> preprocessor statement is used to include the text of another file, which may also contain preprocessor directives. The latest IBM compilers also provide an '''<code>%XINCLUDE'''</code> directive, which has the effect of including the specified file only if it has not already been included.
'''<code>%INSCAN'''</code> and '''<code>%XINSCAN'''</code> operate similarly, except that the name of the file to be included is specified by a preprocessor expression.
 
==Listing control==
Line 15:
Listing control statements provide instructions for formatting both the listing generated by the preprocessor and the listing generated by the compiler.
 
*'''{{code|%PRINT;'''}} causes the printing of listings of the following text to be started or resumed.
*'''{{code|%NOPRINT;'''}} causes the printing of the listings of the following text to be suppressed.
*'''{{code|%PAGE;'''}} causes a new page to be started in the listings.
*'''{{code|%SKIP [(n)];'''}} causes '<var>n'</var> lines to be skipped in the listings. If '<var>n'</var> is omitted the default is one line.
*'''{{code|%PUSH'''}}, '''{{code|%POP'''}} save and restore the current status of {{code|%PRINT}}/{{code|%NOPRINT}} on a pushdown stack and restore it, respectively.
 
==Preprocessor operation==
 
The preprocessor operates by scanning the input text and recognizing declared ''preprocessor names'', also called ''preprocessor identifiers''. The text is copied to the preprocessor output with the preprocessor names replaced with their current values. The name may represent a call to a ''preprocessor procedure'' ([[Macro_Macro (computer_sciencecomputer science)|macro)]]). Replacement text may be rescanned by the preprocessor for possible additional replacement.
 
===Preprocessor data types===
 
Preprocessor data may be declared to be <code>CHARACTER</code>, a character string with no maximum length, or <code>FIXED</code> an integer number of up to five decimal digits. A ''preprocessor builtin'' is a predefined procedure operating on preprocessor data. A ''preprocessor expression'' is an expression consisting only of preprocessor names, references to preprocessor procedures or builtins, and decimal or character constants. There are no <code>BIT</code> variables, but a <code>BIT</code> result may be obtained by comparison. The expression in <code>%IF</code> evaluates to <code>BIT</code>. All PL/I operators are allowed except exponentiation.
 
===Preprocessor statements===
 
*'''{{code|%DECLARE'''}} establishes an identifier as a preprocessor variable, either {{code|CHARACTER}} or {{code|FIXED}}.
*%assignment assigns a value to a preprocessor identifier.
*'''{{code|%ACTIVATE'''}} makes a preprocessor identifier active, that is, eligible for replacement when encountered in the input text.
*'''{{code|%DEACTIVATE'''}} makes a preprocessor ineligible for replacement.
*'''{{code|%DO'''}} heads a preprocessor {{code|DO}}-group, which is used to group statements and possibly specify iteration. A preprocessor {{code|DO}}-group can contain any combination of preprocessor statements and input text.
*'''{{code|%PROCEDURE'''}} heads a preprocessor procedure, a set of preprocessor statements that functions as a macro returning a value when its name is encountered in the input text.
*'''{{code|%SELECT'''}} heads a preprocessor [[Switch_statementSwitch statement|{{code|SELECT}}-group]].
*'''{{code|%END'''}} terminates a preprocesorpreprocessor {{code|DO}}-group, {{code|SELECT}}-group, or preprocessor procedure.
*'''{{code|%GOTO'''}} (or {{code|%GO TO}}) causes the preprocessor to continue its scan at the specified preprocessor label, either a preprocessor statement or an arbitrary point in the input text.
*'''{{code|%IF'''}} controls the flow of the preprocessor scan according to the value of a preprocessor expression.
 
<pre>
%IF preprocessor-expression
%THEN preprocessor unit1
%ELSE preprocessor-unit2
</pre>
The preprocessor-units can be any single preprocessor statement or a preprocessor {{code|DO}}-group.
*'''{{code|%ITERATE'''}} transfers control to the {{code|%END}} of the containing preprocessor {{code|DO}}-group, ending the current iteration and beginning the next if needed.
*'''{{code|%LEAVE'''}} terminates any remaining iterations of the containing preprocessor {{code|DO}}-group transfers control to the {{code|%END}}.
*'''{{code|%NOTE'''}} generates a user-specified preprocessor diagnostic message.
*{{code|%null}} is a preprocessor statement consisting only of an optional statement label and a '[[semicolon]] ({{code|;'}}). It does nothing, but serves aas a placeholderplace-holder where a required statement is not needed.
*'''{{code|%REPLACE'''}} allows immediate replacement of a ''name'' by a character or fixed expression. The ''name'' does not have to be a declared preprocessor identifier.
 
===Preprocessor builtinsprocedures===
A preprocessor procedure is a [[subroutine]] executed by the preprocessor. The procedure is delimited by <code>%PROCEDURE</code> and <code>%END</code> statements and can contain only preprocessor statements, without the leading <code>%</code>. It is invoked as a function reference from ''open code'', outside of any preprocessor procedure, or from another preprocessor procedure, and returns a <code>CHARACTER</code> or <code>FIXED</code> value. When the procedure is invoked from open code the arguments are passed ''by name'', that is they are interpreted as character strings delimited by commas or a right parenthesis, all leading, trailing, or embedded blanks are significant and considered part of the argument.<ref name=ibm3lr40>{{cite book|last=IBM Corporation|title=Enterprise PL/I for z/OS PL/I for AIX WebSphere Developer for zSeries PL/I for Windows Language Reference|year=2005|url=http://pic.dhe.ibm.com/infocenter/pdthelp/v1r1/topic/com.ibm.entpli.doc_3.5/ibm3lr40.pdf}}</ref>{{rp|pp.508–509}}
 
==Preprocessor built-ins==
These are the builtins for IBM's ''PL/I for MVS and VM'' compiler.<ref name=PLI1.1>{{cite book|last=IBM Corporation|title=IBM PL/I for MVS & VM Language Reference|year=1995}}</ref>{{rp|pp.404-406}} There can be considerable difference between preprocessors of various PL/I compiler in the builtins provided.
 
* '''COMPILETIME''' &mdash; returns the date and time of compilation as a character string such as "15 SEP 12 15:30:00".
These are the builtinsbuilt-ins for IBM's ''PL/I for MVS and VM'' compiler.<ref name=PLI1.1>{{cite book|last=IBM Corporation|title=IBM PL/I for MVS & VM Language Reference|year=1995}}</ref>{{rp|pp.404-406404–406}} There can be considerable difference betweenin the built-ins provided among preprocessors of various PL/I compiler in the builtins providedcompilers.
* '''COUNTER''' &mdash; returns a character string containing a number that is "00001" for the first call to COUNTER and increases by one for each subsequent call.
* '''{{code|COMPILETIME'''}} &mdash; returns the date and time of compilation as a character string such as "15 SEP 12 15:30:00" for September 15, 2012 3:30PM (local time).
* '''INDEX''' &mdash; same as PL/I builtin INDEX.
* '''{{code|COUNTER'''}} &mdash; returns a character string containing a number that is "00001" for the first call to {{code|COUNTER}} and increases by one for each subsequent call.
* '''LENGTH''' &mdash; same as PL/I builtin LENGTH.
* '''{{code|INDEX'''}} &mdash; same as PL/I builtin {{code|INDEX}}.
* '''PARMSET''' &mdash; PARMSET(p) returns '1'b if the argument 'p' was set in the current call to this preprocessor procedure, otherwise '0'b.
* '''SUBSTR'''{{code|LENGTH}} &mdash; same as PL/I builtin SUBSTR{{code|LENGTH}}.
* '''{{code|PARMSET'''}} &mdash; {{code|PARMSET(p)}} returns {{code|'1'b}} if the argument '{{code|p'}} was set in the current call to this preprocessor procedure, otherwise {{code|'0'b}}.
* '''LENGTH'''{{code|SUBSTR}} &mdash; same as PL/I builtin LENGTH{{code|SUBSTR}}.
 
==Example==
The following example for IBM PL/I for OS/2 illustrates the use of a preprocessor procedure to implement a C-like write statement for PL/I.<ref>{{cite web|last=Sturm|first=Eberhard|title=UIO-Makros für Builtin-Funktionen fileread und filewrite|url=https://www.uni-muenster.de/ZIV.EberhardSturm/uio.cpy|access-date=January 22, 2012}}</ref> The procedure would be called by coding the statement {{code|uwrite file(filename) from(varying_string) count(byte_count);}} {{mono|<var>Byte_count</var>}} is optional and defaults to the length of {{mono|<var>varying_string</var>}} if omitted.
<syntaxhighlight lang="rexx" line highlight="1,25,26">
%uwrite:
procedure keys (File, From, Count);
 
dcl (File, From, Count, Number, Size) char;
 
if parmset(File) & parmset(From) then; else do;
note ('FILE and FROM must be specified!', 12);
return;
end;
 
if parmset(Count)
then Size = 'min(length(' || From || '), ' || Count || ')';
else Size = 'length(' || From || ')';
 
Number = Counter();
ans ('do;');
ans ('dcl Count' || Number || ' fixed bin (15);' ) skip;
ans ('Count' || Number || ' = filewrite('
|| File
|| ', ptradd(addr(' || From || '), 2)'
|| ', ' || Size
|| ');') skip;
ans ('end;') skip;
 
%end;
%act uwrite;
</syntaxhighlight>
 
The statement {{code|uwrite file(file_name) from(var_str) count(64);}} generates the following:
<syntaxhighlight lang="rexx">
do;
dcl Count00001 fixed bin (15);
Count00001 = filewrite(file_name, ptradd(addr(var_str), 2), min(length(var_str), 64));
end;
</syntaxhighlight>
 
==Evolution==
A 1964 report on "NPL",<ref>{{cite book|last=IBM Corporation|title=NPL Technical Report|year=1964|url=http://bitsavers.informatik.uni-stuttgart.de/pdf/ibm/360/pli/320-0908_NPL_Technical_Report_Dec64.pdf}}</ref>{{rp|pp.109–114}} as PL/I was called at the time, provided that macro procedures, identified by the keyword <code>MACRO</code>, could use the complete facilities of the language. The following compile-time statements were allowed in open code:
* <code>%DECLARE</code> &ndash; both fixed-length and varying character strings were defined.
* <code>%<var>assignment</var></code>
* <code>%<var>null statement</var></code>
* <code>%IF <var>compile_time_comparison</var> THEN <var>unit</var> [ELSE <var>unit</var>]</code> &ndash; this causes one or the other <var>unit</var> to be included in the source.
* <code>%GOTO</code>
 
"NPL" as defined in this manual was never implemented.
 
In 1965 an update to IBM's ''PL/I Language specification'' defined an even less ambitious preprocessor language.<ref>{{cite book|last=IBM Corporation|title=IBM Operating System/360 PL/I: Language Specifications (C28-6571-1)|year=1965|url=http://bitsavers.informatik.uni-stuttgart.de/pdf/ibm/360/pli/C28-6571-1_PL_I_Language_Specifications_Jul65.pdf}}</ref>{{rp|pp.131–133}} All mention of preprocessor procedures was omitted. The following compile-time statements were specified:
* <code>%DECLARE</code>
* <code>%<var>assignment</var></code>
* <code>%<var>null statement</var></code>
* <code>%IF <var>compile_time_comparison</var> THEN GOTO <var>label</var></code> &ndash; No <code>ELSE</code> clause was defined.
* <code>%GOTO</code>
 
This language specification was again never implemented, however a 1966 revision of this manual restored preprocessor procedures with the now-current {{code|%PROCEDURE ... %END}} syntax and brought the specification close to what was actually included in PL/I(F).<ref>{{cite book|last=IBM Corporation|title=IBM Operating System/360 PL/I: Language Specifications (C28-6571-3)|year=1966|url=http://bitsavers.informatik.uni-stuttgart.de/pdf/ibm/360/pli/C28-6571-3_PL_I_Language_Specifications_Jul66.pdf}}</ref>{{rp|pp.132–139}}<ref>{{cite book|last=IBM Corporation|title=IBM System/360 PL/I Reference Manual (C28-8201-3)|year=1969|url=http://bitsavers.informatik.uni-stuttgart.de/pdf/ibm/360/pli/C28-8201-1_PLIrefMan_Jan69.pdf}}</ref>{{rp|pp.154–162}} Fixed-length character variables were gone. New statements added were:
* <code>%ACTIVATE</code>
* <code>%DEACTIVATE</code>
* <code>%DO [<var>preprocessor_variable</var> = <var>preprocessor_expression</var> TO <var>preprocessor_expression</var> [BY <var>preprocessor_expression</var>]]</code>
* <code>RETURN</code> in a compile-time procedure only.
* <code>%INCLUDE</code>
* <code>%IF</code> &ndash; the <code>%IF <var>compile_time_comparison</var> %THEN <var>unit</var> [%ELSE <var>unit</var>]</code> was restored.
 
A single compile-time builtin, <code>SUBSTR</code>, was added.
Also in 1966 Robert Rosin published a pair of articles<ref>{{cite journal|last=Rosin|first=Robert|title=PL/I Macro Processor - Progress Report|journal=PL/I Bulletin|date=August 1966|issue=2|url=http://www.iron-spring.com/PLI_Bulletins/PLI_Bulletin_2.pdf|access-date=January 22, 2013}}</ref><ref>{{cite journal|last=Rosin|first=Robert|title=Macros in PL/I|journal=PL/I Bulletin|date=August 1966|issue=2|url=http://www.iron-spring.com/PLI_Bulletins/PLI_Bulletin_2.pdf|access-date=January 22, 2013}}</ref> discussing development of the preprocessor. This development was based in a "[[SHARE (computing)|SHARE]] XXVI Memo" from earlier the same year and a paper by Mark Elson. Rosin credits [[MAD (programming language)|MAD]] as the only previous example of a macro processor in a high-level language.
 
==See also==
* [[C preprocessor]]
 
==References==
Line 69 ⟶ 143:
==External links==
*{{cite web
|url = http://publibfp.boulder.ibm.com/cgi-binepubs/bookmgr/BOOKSpdf/ibm3lr80/21.0?DT=20091014225516pdf
|title = Enterprise PL/I Language Reference (SC27-1460-09): Chapter 21. Preprocessor Facilities
|author = IBM Corporation
|date = October 2009
|accessdateaccess-date = Jan 19, 2012
}}
 
Line 80 ⟶ 154:
|title = Micro Focus Documentation: Open PL/I Macro Preprocessor
|author = Micro Focus International plc
|dateyear = 2011
|accessdateaccess-date = Feb 14, 2012
}}
 
Line 88 ⟶ 162:
|title = Kednos PL/I for OpenVMS Systems Reference Manual: Chapter 10 Preprocessor
|author = Kednos Enterprises
|dateyear = 2007
|accessdateaccess-date = Feb 14, 2012
}}
 
*{{cite web
|url = https://sites.google.com/site/plipreproc/
|title = PL/I Preprocessor Wiki
|author = Peter Flass
| year = 2010
|access-date = 2017-12-06
}} Comparison of preprocessor features
 
{{DEFAULTSORT:PL I preprocessor}}
[[Category:PL/I programming language family]]
[[Category:IBM software]]