FOR

FOR.. 1

Format 1

Function. 1

INDEX, TABLE, EACH.. 1

FOR INDEX.. 1

FOR TABLE.. 3

FOR EACH – Coded variables. 3

TESTNEW... 4

WHERE, UNTIL. 5

 

Format

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

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

      [EACH] Coded-variable} TESTNEW

      [WHERE condition] [UNTIL condition];

      Statements

END FOR [UNTIL condition];

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.

 

It is helpful to think of there being several formats for a FOR statement: FOR INDEX, FOR TABLE, and FOR EACH. The keywords INDEX, TABLE, and EACH are optional **, with Jazz working out which kind of statement based on the type of the 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(JZ.IX1);

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 in the Jazz Sundry Data definition, JZ.  Thus with the FOR statement above IX will become JZ.IX1.  JZ will always contain standard fields IX1 to IX7, whether they are used or not.

 

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 JZ.IX1 = 12 TO 1 STEP -1; 

 

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

            FOR JZ.IX1 = 1;

is actually a loop, not a single iteration of the following statements.  There will be a message if there is no UNTIL option on the corresponding END.

 

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

            FOR JZ.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 JZ.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 JZ.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;

 

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 JZ, 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 FOR INDEX, if the index fields don’t already exist they will be created as SMALLINT fields.

 

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(JZ.IX1, JZ.IX2, JZ.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.

 

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).

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, JZ.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(JZ.IX2)) cause an error message, so would FOR W.NameInGrp(JZ.IX2);.  However you can’t always put the references to W.NameInGrp within FOR W.NameInGrp(JZ.IX2, JZ.IX2).  For example: -

FOR W.Grp(JZ.IX1);

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

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

        PRINT(W.NameInGrp(JZ.IX1,JZ.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, JZ.IX2) TESTNEW;

        PLINE (,IN1D2.District ,IN1D2.Name ,IN1D2.Sales(1,JZ.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, UNTIL

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

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

                PRINT

            END FOR;

loops varying JZ.IX from 1 to 10, but skipping values of JZ.IX for which R.Table(JZ.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  JZ.IX = 4, 6 or 9.

 

UNTIL will terminate the loop. 

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

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

 

UNTIL can be attached to the END FOR statement if you want testing to occur at the end of the loop.  UNTIL clauses can be used on either or both the FOR and END FOR statements, and can be combined with WHERE on the FOR statement.

 

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

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

as from

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

and even

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

 

The logic of a FOR statement with a positive STEP value and WHERE and UNTIL options, and an UNTIL option on the END statement, is as follows: -

 

            Set Numeric-Variable to Initial Value

Loop:

IF Numeric-Variable > Limit OR Until condition is true Or the End-Until condition was true THEN

            GO TO ExitLoop

IF WHERE condition on FOR is false THEN

            GO TO CycleLoop

 

Do statements from FOR to END FOR

 

If End-Until condition is true THEN

            Set a flag that is tested after Loop

CycleLoop:

Add Step Increment to Numeric Variable

GO TO Loop

ExitLoop:

            Continue with statements following END FOR