FOR

FOR.. 1

Format 1

Function. 1

INDEX, TABLE, EACH.. 1

FOR INDEX.. 1

FOR TABLE.. 1

FOR EACH – Coded variables. 1

TESTNEW... 1

WHERE, WHILE, UNTIL. 1

FOR Statement Logic. 1

Predefined Fields. 1

Flags. 1

Index Fields. 1

 

Format

FOR { [INDEX] [Numeric-variable = Start [TO Limit] [STEP Increment]] |

      [TABLE] Table-variable (Index name [, Index name]…) |

      [EACH] Coded-variable} TESTNEW}

      [WHERE condition] [WHILE condition] [UNTIL condition];

      Statements

END FOR;

Function

The FOR statement is used in situations such as processing every element of a table.

Thus

DEFINE Area DATA(

            MonthlySales(12) MONEY(5,2));

FOR Work.Mth = 1 TO 12;

            PRINT (Area.MonthlySales(Work.Mth));

END FOR;

prints each value of Monthly sales. Mth will have been defined somewhere, preferably as a SMALLINT field: if Jazz can’t find a suitable definition it will create one. A number of pre-defined fields like IX1 are defined for you in JZ2, allowing you to simply refer to them.

 

It is helpful to think of there being several formats for a FOR statement: FOR INDEX, FOR TABLE, FOR EACH, FOR WHILE, and FOR UNTIL. The keywords INDEX, TABLE, and EACH are optional **, with Jazz working out which kind of statement based on the type of the initial variable: -

a.         If the variable has a CODES option, then this is a FOR EACH statement

b.         If the variable has one or more dimensions, then this is a FOR TABLE statement

c.         If the variable is a scalar number (i.e., has no unspecified dimensions), then this a FOR INDEX statement.

 

**         INDEX, TABLE, and EACH will be interpreted as field names if possible.  For example

DEFINE AMax PARAMETERS ANY DATA(

    Table(100) DECIMAL(7,2) INPUT,

    MaxValue DECIMAL(7,2) OUTPUT);

FOR Table(IX1);

becomes

FOR AMax.Table(JZ2.IX1);

 

WHILE and UNTIL options can be used with any of these three forms, and like EACH, TABLE, or INDEX will terminate the loop.  Thus

FOR Work.Mth = 1 TO 12 UNTIL SALES(Work.Mth) > 1000;

 

You can also use WHILE and UNTIL on their own, for example

            FOR WHILE EZT-OU278A00-Data.WFIM <> '*';

This is a loop that will be executed repeatedly, until an iteration finds the condition to be false.   UNTIL is exactly the same except that the loop will be terminated when the condition is true.

 

WHERE is neither: the loop will be controlled by it’s other conditions, but on every iteration the WHERE condition is tested, and if it is false that iteration will be skipped.  Thus with the FOR above,

FOR Work.Mth = 1 TO 12 UNTIL SALES(Work.Mth) > 1000;

If SALES(Work.Mth) > 1000 is true when Work.Mth = 5 then the loop will only process the first 4 values.  However with

FOR Work.Mth = 1 TO 12 WHERE SALES(Work.Mth) > 1000;

all 10 values will be examined, but only those for which the condition is true are processed by the statements between FOR and END FOR;

 

INDEX, TABLE, EACH

The various forms of FOR statement are used like this: -

FOR INDEX

FOR [INDEX] Numeric-variable = Start [TO Limit] [STEP Increment]

This is the common form where you specify the starting and ending value of the loop, e.g.

            FOR IX1 = 1 TO 12;

 

The keyword INDEX is optional. It will usually be omitted as this form of FOR statement is then very similar to loop statements in other languages.

 

If the index variable does not exist, it will be created for you in the Jazz Sundry Data definition, JZ.  Thus if you write

FOR IY = 1 TO 10;

END FOR;

This will become

FOR JZ.IY = 1 TO 10;

END FOR;

Or you might use one of the predefined index variables named starting with IX, which become (e.g.) JZ2.IX1.  See Predefined Fields below.

 

STEP defines the step increment: if omitted (as here), STEP(1) is assumed. It may be negative, in which case the loop “runs backwards”, e.g.

            FOR JZ2.IX1 = 12 TO 1 STEP -1; 

 

You can omit TO when you want the loop to be terminated by the UNTIL or WHILE condition, or by a statement within the loop.  Since STEP will also default, to STEP 1,

            FOR JZ2.IX1 = 1;

is actually a loop, not a single iteration of the following statements.  There will be a message if there is no TO, UNTIL or WHILE condition.

 

Start, Limit, and Increment may all be numeric fields instead of numeric constants. For example

            FOR JZ2.IX1 = RECORD.START TO RECORD.STOP STEP RECORD.STEP;

Jazz uses the values of these fields when the loop starts.  Thus if the fields have these values on entry to the FOR: -

            RECORD.START = 5;

            RECORD.STOP = 10;

            RECORD.STEP = 2;

then this FOR loop is equivalent to

            FOR JZ2.IX1 = 5 TO 10 STEP 2;

Any assignment to these fields has no effect on the loop once it has started. Thus even if the loop executes the IF statement setting RECORD.STOP to zero, the loop continues to execute until a value of JZ2.IX1 exceeds 10: -

            FOR IX1 = RECORD.START TO RECORD.STOP STEP RECORD.STEP;

                IF RECORD.Value > 10 THEN

                        RECORD.STOP = 0;  [This DOES NOT stop the loop

                END IF;

               

            END FOR;

 

The numeric variable, IX1 in our example, must be a scalar SMALLINT field: there will be messages if it has a dimension, or another format.

 

You can refer to the numeric variable, but you should not change its value. Jazz uses hidden fields that you can’t reference to protect you from the errors that could result, but it can’t cover all error possibilities. Thus the following code can’t possibly be correct, but Jazz cannot detect the error: -

PROGRAM ScrewUp;

    FOR IX1 = 1 TO 10;

        PERFORM Routine1;

        PRINT (TableValue(IX1));

    END FOR;

ROUTINE Routine1;

    FOR IX1 = 20 TO 25;

       

    END FOR

 

On reading the first loop in ScrewUp, FOR IX1 = 1 TO 10;, one would naturally expect PRINT (TableValue(IX1)); to print the 1st, 2nd, 3rd, … 10th value of TableValue.  However although the first loop will be executed 10 times, which is correct, it will attempt to print TableValue(26) every time, which is not.

FOR TABLE

FOR [TABLE] Table-Variable (Index name [, Index name]…)

Since FOR statements are often used to iterate through a table, Jazz provides a form especially for this. Write

      FOR Table(IX1, IX2)

to iterate through the 2-d table “Table” using indexes IX1 and IX2. Thus if you’ve defined Table as

            DEFINE D DATA(

                Table (5, 12) CHAR(10));

then this loop is equivalent to a pair of nested loops: -

FOR IX1 = 1 TO 5;

    FOR IX2 = 1 TO 12;

       

    END FOR;

END FOR;

 

For iterating through a table you should use this form of FOR rather than the first form. Its advantage is that the table bounds are automatically built into the loop, and that Jazz can check that you’ve given the correct number of indexes. Also, this form allows Jazz to generate efficient code, which it can’t always do with FOR INDEX (form 1), and an extra bonus: if you later change the dimensions of the table, the FOR loop will be automatically corrected when you next edit the program.

 

The index fields can be named anything you like, they do not have to be named IX1, IX2, etc.  However fields with these names are always defined into definition JZ2 whether you use them for this purpose or not, and it is recommended that you follow a rule of naming indexes IX1 to IX7 wherever possible.

 

As with INDEX, the keyword TABLE is optional and may be omitted.   It MUST be omitted you have a field named “table” anywhere in your program.  For example if this is present: -

DEFINE TablData PARAMETERS ANY DATA(

    Table (100) DECIMAL(7,2) INPUT, …

and you want to use “FOR Table” to process your own table: -

DEFINE MyData DATA(

    MyTable (5,10,2) SMALLINT, …

you can do this by writing

For MyTable(IX1, IX2, IX3);

which will become 

FOR MyData.MyTable(JZ2.IX1, JZ2.IX2, JZ2.IX3);

 

However if you write

For Table MyTable(IX1, IX2, IX3);

“Table” will be interpreted as a reference to TablData.Table, and the FOR statement will be invalid.

 

Table Cross Sections and Tables within Tables

To process a table “cross-section”, i.e. part of a table in which one or more subscripts are held constant, you can write a TABLE loop naming NULL as an index.  For example, with IN1D2.Sales defined

            Sales(3,7) DECIMAL(7,2),

you can write

          FOR IN1D2.Sales(NULL, JZ2.IX2);

to process the 7 members of a particular set of Sales.  This FOR is now equivalent to the single FOR INDEX statement

FOR IX2 = 1 TO 7;

 

This is particularly useful when a table is defined within another table.  For example: -

DEFINE W DATA(

    Grp(3) GROUP,

        Location CHAR(30),

        NameInGrp(2) CHAR(37),

       

 

NameInGrp is actually a table with two dimensions, so you will get error messages unless references to it have both dimensions. Thus not only would PRINT(W.NameInGrp(JZ2.IX2)) cause an error message, so would FOR W.NameInGrp(JZ2.IX2);.  However you can’t always put the references to W.NameInGrp within FOR W.NameInGrp(JZ2.IX2, JZ2.IX2).  For example: -

FOR W.Grp(JZ2.IX1);

    PRINT(W.Location(JZ2.IX1));

    FOR W.NameInGrp(NULL, JZ2.IX2);

        PRINT(W.NameInGrp(JZ2.IX1,JZ2.IX2));

    END FOR;

END FOR;

FOR EACH – Coded variables

FOR [EACH] Coded-Variable

A loop may iterate through all the possible values of a coded variable. Thus with fields defined like this: -

DEFINE Recrd DATA(

        Sex CHAR(1) CODES(M:Male, F:Female),

        Region DECIMAL(1) CODES(1:'New Zealand', 2:Australia, 5:'United Kingdom'));

 

you can write a loop like this to iterate through the values M:Male, and F:Female

FOR EACH Recrd.sex;

    PRINT (Recrd.sex);

END FOR;

 

Similarly

FOR EACH Recrd.Region;

   

END FOR;

would iterate through the values of Region.

 

The coded field must not have a dimension.

 

As before, the keyword EACH may be omitted.

TESTNEW

This statement option is used when FOR is used with a PLINE statement.

    FOR IN1D2.Sales(Null, JZ2.IX2) TESTNEW;

        PLINE (,IN1D2.District ,IN1D2.Name ,IN1D2.Sales(1,JZ2.IX2) );

    END FOR;

With IN1D2.Sales defined with dimension (3,7) the FOR loop prints 7 lines.  Because of TESTNEW scalar (non-repeating) fields are not printed for dimensions 2 to 7 unless the line is on a new page.

      District    *----Name-----*      *-Sales--*

Region    1    New Zealand                      

             1    BLEE,ElliottLin           78.00

                                            79.00

                                            80.00

                                            81.00

                                            82.00

                                            83.00

                                            84.00

             1    HANNAH,Honour            241.00

                                           242.00

                                           243.00

Without the TESTNEW option this report looks like this: -

Region    1    New Zealand                      

             1    BLEE,ElliottLin           78.00

             1    BLEE,ElliottLin           79.00

             1    BLEE,ElliottLin           80.00

             1    BLEE,ElliottLin           81.00

             1    BLEE,ElliottLin           82.00

             1    BLEE,ElliottLin           83.00

             1    BLEE,ElliottLin           84.00

             1    HANNAH,Honour            241.00

             1    HANNAH,Honour            242.00

WHERE, WHILE, UNTIL

Adding a WHERE condition causes the loop to be skipped if the WHERE condition is true. Thus

            FOR JZ2.IX = 1 TO 10 WHERE R.Table(JZ2.IX) <> 35;

                PRINT

            END FOR;

loops varying JZ2.IX from 1 to 10, but skipping values of JZ2.IX for which R.Table(JZ2.IX) is 35.  Thus if the values of R.Table are 1, 15, 30, 35, 48, 35, 70, 80, 35, 12 the PRINT will be executed 7 times, as it won’t be executed when  JZ2.IX = 4, 6 or 9.  The loop above is equivalent to

            FOR JZ2.IX = 1 TO 10;

    IF R.Table(JZ2.IX) <> 35;

                    PRINT

                END IF;

            END FOR;

 

WHILE and UNTIL will terminate the loop. 

      FOR JZ2.IX = 1 TO 10 UNTIL R.Table(JZ2.IX) = 35;

With the values of R.Table above this will execute the loop for JZ2.IX = 1 to 3, but on the fourth value the condition is true and the loop is terminated.

 

Whereas UNTIL terminates the loop when the condition is true, WHILE terminates it when the condition is false.  With R.Table values as above,

      FOR JZ2.IX = 1 TO 10 WHILE R.Table(JZ2.IX) = 35;

immediately terminates the FOR loop, so it is never executed.  However if the values of R.Table had been 35, 35, 35, 35, 48, 35, 70, 80, 35, 12 then the loop would have been executed for JZ2.IX = 1 to 4, but be terminated for JZ2.IX = 5 when R.Table(JZ2.IX) = 48.

 

It may be valid to use WHILE, and UNTIL as the only FOR options.  For example,

        FOR WHILE EZT-TEST-Data.WS-IN-FINE-DEDUPLIC = 'N' & EZT-TEST-Data.WS-IN-ABBINATO-DEDUPLIC = 'N' & DEDUPLIC.AN400-CD-NDG <= CONVE.CONVE-CD-CONVENZIONATO;

            IF DEDUPLIC.AN400-CD-NDG = CONVE.CONVE-CD-CONVENZIONATO;

                EZT-TEST-Data.WS-IN-ABBINATO-DEDUPLIC = 'S';

            ELSE;

                PERFORM LEGGI-DEDUPLIC;

            END IF;

        END FOR;

Note that without an implied INDEX, TABLE, or EACH option there is no implied loop increment or termination, so it is essential that the loop body includes logic to terminate the loop when appropriate. Here PERFORM LEGGI-DEDUPLIC reads a record, and the logic of this routine is

ROUTINE LEGGI-DEDUPLIC;

    GET DEDUPLIC NEXT;

    IF DEDUPLIC.$Endfile;

        EZT-TEST-Data.WS-IN-FINE-DEDUPLIC = 'S';

        DEDUPLIC.AN400-CD-NDG = 999999999999999999;

    END IF;

END ROUTINE LEGGI-DEDUPLIC;

so that when ENDFILE is reached (DEDUPLIC.$Endfile is true) the WHILE condition will be false with the next iteration of the FOR statement.

 

A FOR statement can use all of the options WHERE, WHILE, and UNTIL with the INDEX, TABLE, or EACH option.  Conditions cannot use LIKE comparisons, although they can use the other “SQL form” conditions IN(value list) and BETWEEN.

 

Note that the order in which you write the statement options has no effect on execution: you get exactly the same results from

          FOR JZ2.IX1 = 1 TO 20 UNTIL In1d.name = 'robert' WHERE IN1D.Sales(JZ2.IX1) > 1000;

as from

          FOR JZ2.IX1 = 1 TO 20 WHERE IN1D.Sales(JZ2.IX1) > 1000 UNTIL In1d.name = 'robert' ;

and even

          FOR JZ2.IX1 = 1 WHERE IN1D.Sales(JZ2.IX1) > 1000 UNTIL In1d.name = 'robert'  TO 20;

FOR Statement Logic

The logic of a FOR statement with a positive STEP value and WHERE, UNTIL and WHILE options is as follows: -

 

            Set Numeric-Variable to Initial Value

Loop:

IF Numeric-Variable > Limit OR Until condition is true OR While condition is false THEN

            GO TO ExitLoop

IF WHERE condition on FOR is false THEN

            GO TO CycleLoop

 

Do statements from FOR to END FOR

 

CycleLoop:

Add Step Increment to Numeric Variable

GO TO Loop

ExitLoop:

            Continue with statements following END FOR

 

With a negative STEP value, the test is

            IF Numeric-Variable < Limit

and      Add Step Increment to Numeric Variable 

=>        Subtract Step Increment From Numeric Variable

Predefined Fields

Jazz has pre-defined a number of fields for you to use anywhere that you want an index (SMALLINT) or flag (BOOLEAN) field.  For example, just write IX1, this will be qualified to JZ2.IX1.  Although all these fields are known to Jazz, they will only be generated into the COBOL program if they are used.

Flags

JZ2 starts with 12 flags, named FLAG1 to FLAG10, plus FLAGNull and SEARCH-FOUND.  For example

    FLAG1 BOOLEAN VALUE false,

Like all BOOLEAN fields, they have initial value False.  FLAGNull and SEARCH-FOUND are used by Jazz, you can refer to them but you shouldn’t set them.

Index Fields

Fields named IX, IX1 to IX10, and IXA to IXZ are defined like

    IX SMALLINT VALUE 0,

and are available for general use.  Fields IXLS, IXL2, and IXNULL may be set by Jazz, like the special flags you can refer to them but you should not set them.