Preprocessor

This chapter describes the basic concept of a preprocessor and how to use it.

1. Overview

A preprocessor receives a source program then changes and displays a part of the source program according to a preprocessor statement.

The output of the preprocessor is used as an input to the complier.

The source program input to a preprocessor consists of three elements.

  • Preprocessor Statement

    A preprocessor statement must begin with a percent sign (%). However, the statements described in a preprocessor procedure do not use a percent sign. Preprocessor statements are executed in the sequence they appear in the source program.

    Preprocessor statements can have the following effect on input texts:

    • Preprocessors execute preprocessor statements in order, and then changes input texts based on the execution.

    • Preprocessor statements can determine whether to change an input text.

    • A string of characters included in another file or library can be included in the preprocessor input.

    The following is the description of tasks that can be done through preprocessor statements.

    Statement Description

    %DECLARE

    Variable name and attribute to be used in a preprocessor.

    Declares that the %ACTIVATE statement was executed so the variable is activated. If a variable is not declared explicitly, it will be declared as a CHARACTER attribute and treated as inactivated.

    %ACTIVATE (abbreviation: %ACT), %DEACTIVATE (abbreviation: %DEACT)

    Option to convert the string of an input text to the value of a preprocessor variable.

    • %ACTIVATE: activates

    • %DEACTIVATE: deactivates

    %INCLUDE

    Strings that are saved in another file can be included in the input to a preprocessor.

    %GOTO, %IF, %DO, %END

    Alters the execution order of a preprocessor.

    %assignment

    Alters the value of a preprocessor variable.

    %PROCEDURE

    Defines and uses a preprocessor procedure.

  • Listing Control Statement

    A listing control statement specifies the layout of a printed program listing. In OpenFrame PL/I, this only affects preprocessor input and not output.

  • Input Text

    An input text represents any preprocessor input other than the aforementioned preprocessor statement or input text. An input text can be either a PL/I source program or any other text. A PL/I constant is displayed as-is without any change. A string that matches the name of an activated preprocessor variable is converted to the value of the variable.

    The RESCAN or NORESCAN option can be set on a preprocessor variable. If the NORESCAN option is set, the value is converted to the processor output only once. If the RESCAN option is set, a rescan is performed until all possible replacements of the value have been made.

Variables and Data

The variables of a preprocessor can be declared using the %DECLARE statement. Variables can be set with the FIXED and CHARACTER attributes. All variables have a static storage class.

The data types of preprocessors are as follows:

Type Description

FIXED

Corresponds to the integer type of Linux C++.

CHARACTER

Corresponds to the std::string type of Linux C++.

A numeric constant only allows an unscaled integer. It does not allow string repetition factors.

References and Expressions

A reference and expression of a preprocessor are evaluated in the same way as explained in Expressions.

Note the following exceptions:

  • The operands of an expression that include preprocessor variables, procedure references, fixed decimal constants, bit constants, character constants, and references to preprocessor built-in functions.

  • Arrays that are declared outside a preprocessor procedure that can be referenced by multiple procedures. However, these arrays cannot be referenced outside a procedure.

  • The exponentiation symbol (**) cannot be used.

  • A decimal fixed-point result that is converted to a precision. For example, 3/5 that is saved as 0, rather than 0.6.

  • A string that can be used in arithmetic operations. However, it must be an integer.

  • A null string that is converted to 0.

  • A fixed-point value that is always converted to the string of 8 characters in length.

Name Scope

The scope of a name used in a preprocessor is determined based on where it is declared.

The scope of a name declared within a procedure is that procedure. The name declared in an included string is referenced by that string and all input text scanned after the string is included.

All other names correspond to an entire preprocessor input. However, a preprocessor procedure where a name is declared is excluded.

2. Procedure

This section describes the basic concepts and rules of a preprocessor procedure.

The basic syntax of a preprocessor procedure is as follows:

figure procedure
Preprocessor Procedure

The understanding of how to send parameters and how to process return values is required for using a preprocessor procedure.

Parameters can be sent as positional and keyword parameters. Keyword parameters are used to send an argument that corresponds to the name of a parameter.

In a positional parameter, an argument is matched with a parameter according to the sequence of the argument. The number of arguments and parameters may not be equal. If the number of arguments is greater than that of parameters, the remainder is ignored. If the number of parameters is greater than that of arguments, all parameter values are initialized. For fixed parameters, the value of zero is given and for CHARACTER parameters, the null string is given.

If a function reference is referenced by an input text, the arguments are delimited by a comma or right parenthesis.

For example, (A(B,C),D) consists of two arguments. Replacement activity is performed before the arguments "A(B,C)" and "D" are passed to the parameter. However, this replacement does not have an effect on the number of arguments. If the arguments are replaced by E,F and become E, F, D due to A(B,C), there are still 2 arguments, "E, F" and "D".

If a reference appears in an input text and the STATEMENT option exists, arguments can be a positional argument or keyword reference. The end of a reference is indicated by a semicolon(;), but the semicolon is not displayed.

The following is an example of a preprocessor procedure:

%FIND:PROC(A,B,C) STATEMENT;

If a preprocessor procedure is declared as shown above, it can be referenced as follows. The following examples have the same meaning:

FIND(X,Y,Z);
FIND B(Y) C(Z) A(X);
FIND(X) C(Z) B(Y);
FIND(,Y,Z) A(X);

An attribute of a value returned by a function procedure is set to CHARACTER or FIXED.

A preprocessor procedure that has the RETURNS attribute must include one or more RETURN statements. The RETURN statement returns the control to the point of invocation. The resulting argument is converted to the value specified in the RETURN statement of the function reference.

The followings are the considerations for using a preprocessor procedure:

  • A preprocessor procedure is delimited by %PROCEDURE and %END.

  • If a procedure does not include the RETURNS attribute, it must not also include the RETURN statement. If a procedure is a function, it must include at least one statement.

  • A preprocessor statement within a preprocessor procedure does not begin with a percent sign (%).

  • A preprocessor procedure cannot be nested.

  • A preprocessor ENTRY cannot be declared within a preprocessor procedure.

  • A preprocessor procedure entry name set with an argument is called a function reference. A function reference can be invoked within a preprocessor expression.

  • A name of a preprocessor procedure does not need to be declared in the %DECLARE statement.

  • When an entry name is activated, the preprocessor procedure does not need to be processed before it is invoked. However, the procedure must be included in the preprocessor input or must be already included before it is invoked.

  • A value that is returned by a preprocessor function replaces the function reference and its argument list.

3. Statements

This section describes how to use preprocessor statements. All statements can be labeled.

3.1. %ACTIVATE Statement (Abbreviation: %ACT)

The %ACTIVATE statement makes an identifier active to convert input text.

All variables of the input texts encountered while an identifier is active are converted to the value of that variable. The replacement activity does not have any effect on the variables that are already active.

figure activate
%ACTIVATE Statement
Component Description

identifier

Name of a preprocessor identifier, procedure, or built-in function.

An array variable cannot be specified.

RESCAN

Specifies that a converted identifier is replaced again if it is the same as the preprocessor after conversion. This activity repeats until there are no more names to be mapped to.

SCAN

Specifies that an identifier is replaced only once.

NORESCAN

Same as SCAN.

3.2. %assignment Statement

The %assignment statement calculates a preprocessor expression and assigns its results to a preprocessor variable.

figure assignment
%assignment Statement

Compound and multiple arguments ( +=, -= , or a = b = c ) are not allowed. The target of an argument cannot be an array.

3.3. %DEACTIVATE Statement (Abbreviation: %DEACT)

The %DEACTIVATE statement makes an identifier active.

figure deactivate
%DEACTIVATE Statement
Component Description

identifier

Name of a preprocessor identifier, procedure, or built-in function.

If an identifier becomes inactive, the identifier will no longer be converted. However the value of the preprocessor identifier will not be lost, so a value does not need to be reassigned when the identifier is reactivated. Reactivation of an inactive identifier does not have any effect.

3.4. %DECLARE Statement

The %DECLARE statement defines an identifier for a preprocessor variable, procedure, or built-in function. In addition, a scanning status can be specified for a variable. (Abbreviation: %DCL for DECLARE, CHAR for CHARACTER, INT for INTERNAL, EXT for EXTERNAL)

figure declare1
%DECLARE Statement(1)

or

figure declare2 main
%DECLARE Statement(2)
Component Description

identifier_description

Name and attribute of a preprocessor identifier.

BUILTIN

Specifies that an identifier is a preprocessor built-in function with the same name.

ENTRY

Specifies that an identifier is a preprocessor procedure. This declaration activates an entry name.

An entry name can be explicitly declared using the name labeled in the %PROCEDURE statement. However, a name declared in this way is initialized with an inactive status.

identifier_description:

image

dimension:

image

attributes:

image

Component Description

CHARACTER

Mapped to the std::string type of Linux C++.

FIXED

Mapped to the integer type of Linux C++.

SCAN

Specifies that an identifier is replaced only once.

RESCAN

Specifies that an identifier is replaced again if a converted value has the name of the preprocessor.

NOSCAN

Makes an identifier inactive.

3.5. %DO Statement

The %DO statement with the matching %END statement defines a DO-group.

DO type 1:

figure do do1
%DO Statement - DO type 1

DO type 2:

figure do do2
%DO Statement - DO type 2

specification1:

image

DO type 3:

figure do do3
%DO Statement - DO type 3

specification2:

image

DO type 4:

figure do do4
%DO Statement - DO type 4

The description of the %DO statement is provided in DO Statement.

A preprocessor %DO statement differs from a compiler DO statement in the following ways:

  • UPTHRU and DOWNTHRU do not exist in a %DO statement.

  • Specification 1 and 2 of a DO type 3 are not iterated in a %DO statement.

  • The %DO SKIP statement, which does not exist in a DO statement, is supported in a %DO statement. The %DO SKIP statement also comments out its matching %END statement.

A preprocessor DO-group can be nested. All preprocessor statements, Input texts, and listing control statements can exist in a DO-group.

3.6. %END Statement

The %END statement is mapped to a %DO, %SELECT, or %PROCEDURE statement to define a group or procedure. The labels that follow an END statement must be a label of a %PROCEDURE, %DO, or %SELECT statement.

figure end
ANYCONDITION

3.7. %GO TO Statement

The %GO TO statement specifies a label of a statement that comes after it.

figure goto
%GO TO Statement
Component Description

label

Can only use a statement within a preprocessor procedure in which a %GOTO statement is defined. A label of a %GOTO statement in an included file can only be set to a statement within the file.

3.8. %IF Statement

The %IF statement control the flow of statement by evaluating a preprocessor expression value. The %IF statement can be nested.

figure if
%IF Statement
Component Description

preprocessor_expression

Value of a preprocessor-expression is evaluated and set to true or false temporarily.

If the preprocessor expression is not a conditional expression and its value is 0, this is evaluated to false and true otherwise.

If true, unit1 is executed. If false, unit2 is executed.

preprocessor_unit

Any preprocessor statement including DO-group and SELECT-group (other than %DECLARE, %PROCEDURE, %END, and %DO).

3.9. %INCLUDE Statement

The %INCLUDE statement includes the specified external text where the statement is specified in the preprocessor input. The included external text is referred to as an included text.

An %INCLUDE statement cannot be nested. Another %INCLUDE statement can exist within an included text.

Preprocessor, Do-groups, SELECT-groups, and other procedures must be defined within a single text. This means that a corresponding %END statement must also exist within the text. The name of an included file is limited to 8 characters in length.

figure include
%INCLUDE Statement

3.10. %INSCAN Statement

Similar to the %INCLUDE statement, the %INSCAN statement includes external text where the statement is specified in the preprocessing input. However, unlike the %INCLUDE statement, the name of an included file can be saved in a preprocessor variable.

figure include
%INSCAN Statement

3.11. %ITERATE Statement

The %ITERATE statement jumps to the %END position of a DO-group that includes the %ITERATE statement. After the iteration of the current %DO statement ends, the next iteration continues if necessary.

figure iterate
%ITERATE Statement
Component Description

label_constant

Must be a label of a DO-group. If omitted, the control jumps to the nearest %END.

3.12. %LEAVE Statement

The %LEAVE statement terminates the iteration of a DO-group that has a %LEAVE statement. It then continues the tasks after the %END statement as if the current DO-group was terminated.

figure leave
%LEAVE Statement
Component Description

label_constant

Must be a label of a DO-group.

Terminates all iterations of the DO-group of the label. If omitted, the nearest DO-group is terminated.

3.13. %null Statement

The %null statement does not perform anything.

figure null
%null Statement

3.14. %REPLACE Statement

The %REPLACE statement replaces a name with a specified string or number. The corresponding name does not need to be declared as a preprocessing variable.

figure replace
%REPLACE Statement
Component Description

identifier

Name to be replaced.

string_constant

String constant as a replacement.

arithmetic_constant

Arithmetic constant as a replacement.

3.15. %SELECT Statement

The %SELECT statement with a matching %END statement creates a SELECT-group.

figure select
%SELECT Statement

4. Preprocessor Built-in Functions

A preprocessor built-in function can be invoked through a function reference. It can be invoked in the same way that a user-defined function is invoked. However, the number of arguments must match exactly.

When an input text calls a built-in function, the name of the function must be active. The name of the function can be activated through the %DECLARE and %ACTIVATE statements. The name of a built-in function is always active in a preprocessor statement. If it is a user-defined procedure name, the procedure is referenced.

The following describes preprocessor built-in functions. For detailed description, refer to the relevant subsection.

Function Description

COMPILETIME

Returns a character string of length 18 that contains the date and time of compilation.

COUNTER

Returns a character string of length 5 that contains a decimal number.

INDEX

Returns the starting position of the first occurrence of y in x as a FIXED type.

LENGTH

Returns the length of the string x as a FIXED type.

PARMSET

Returns whether or not the specified parameter was set when the procedure was invoked.

SUBSTR

Returns a substring specified by y and z in x.

4.1. COMPILETIME

COMPILETIME returns an 18 character string that includes date and time.

figure compiletime
Preprocessor Built-in Function: COMPILETIME
  • Return Value

    A return value is returned in the following format:

    DD.MMM.YYbHH.MM.SS

    The following is an example of a return value:

    01.JAN.14 12.01.59

4.2. COUNTER

COUNTER returns a 5 digit character string that includes a decimal number.

figure counter
Preprocessor Built-in Function: COUNTER

It COUNTER is invoked for the first time, the value is 00001 and it is incremented by 1 the next time COUNTER is invoked. After COUNTER is invoked 99999 times, it is reset to 00000 at the next invocation.

4.3. INDEX

INDEX returns a FIXED value indicating the first position within x of y. The location where processing begins can be also specified.

figure index
Preprocessor Built-in Function: INDEX
  • Argument

    Component Description

    x

    String to be searched.

    If it is not a CHARACTER type, it is converted to a CHARACTER type.

    y

    String used for searching.

    If it is not a CHARACTER type, it is converted to CHARACTER type.

    n

    Position within x to start the search.

    If it is not a FIXED type, it is converted to a FIXED type.

  • Return Value

    • 0 is returned when x does not exist in y or the length of y is 0.

    • n must be greater than 0 or less than the length of x +1. If n is the same as the length of x +1, 0 is returned.

4.4. LENGTH

LENGTH returns a fixed value specifying the length of a specified character string x.

figure length
Preprocessor Built-in Function: LENGTH
  • Argument

    Component Description

    x

    If x is not a CHARACTER type, it is converted to a CHARACTER type.

4.5. PARMSET

PARMSET returns a 0 or 1 that indicates whether a parameter was set when a procedure was invoked.

figure parmset
Preprocessor Built-in Function: PARMSET
  • Argument

    Component Description

    x

    Must be a parameter of a preprocessor procedure.

  • Return Value

    • If x is set, 1 or 0 is returned.

4.6. SUBSTR

SUBSTR returns a substring specified by y and z of x.

figure substr
Preprocessor Built-in Function: SUBSTR
  • Argument

    Component Description

    x

    Expression that specifies a string from which a substring is extracted.

    If it is not a CHARACTER type, it is converted to a CHARACTER type.

    y

    Expression that specifies a starting position to extract a substring of x.

    If it is not a CHARACTER type, it is converted to a FIXED type.

    z

    Expression that specifies the length of a substring of x.

    If it is not a CHARACTER type, it is converted to a FIXED type. If z is 0, the string null is returned. If z is omitted, it will return the position y of x to the end of x.

    The value of z cannot be a negative value. The values of y and z must be within a range where a substring of x can be extracted.

  • Return Value

    • If y = LENGTH(x) + 1 and z = 0, the null string is returned.