The CASE structure is used to control sections of the program. CASE offers greater readability than IF-THEN-ELSE when a high level of nesting is required or when the control structure is controlling several dozen lines of code. This is, in part, due to the inherent nature of CASE to separate the logic from the processes.
RPG supports both in-line and subroutine forms of CASE. The CASxx operation performs subroutines while the SELECT-WHEN-OTHER operations perform in-line code. The Boolean operators for CASxx and WHEN operations are the same as those listed in Table 8.3. The CASE operations are considered choice constructs. Figure 8.11 shows the logic flow for the CASE structure.
Figure 8.11: The two forms of CASE.
The primary difference between the two forms of CASE (shown in Figure 8.11) is that the logic flow illustrated to the right includes a default process and the logic flow to the left has no default process.
In Example 8.6, the WHEN operations, like the IF-ELSE-ENDIF operations, can be difficult to distinguish from the other operations. This can force the programmer to interpret each line of code (i.e., the process) even if all that is needed is to check the logic (i.e., choice) of the program.
Example 8.6: In-line CASE using SELECT/WHENxx/OTHER.
.....CSRn01..............OpCode(ex)Extended-factor2+++++++++++++++++++++++++++++ .....CSRn01Factor1+++++++OpCode(ex)Factor2+++++++Result++++++++Len++DcHiLoEq.... C Select C When FieldA = FieldB C Eval Answer = 'A = B' C Add A B C Div Cost MARKUP C When FieldA > FieldB C Eval Answer = 'A > B' C Sub A B C Div Cost PRICE C When FieldA < FieldB C Eval Answer = 'A < B' C Eval MarkUp = Price - Cost C If MarkUp 0 C Div MarkUp PRICE C endIf C When FieldA FieldB * *** This WHEN block would never run C Eval Answer = 'A B' C Add MarkUp YTDProfit C endSl
Complex or multiple conditions, such as those illustrated in Example 8.6, are necessary from time to time. In-line CASE statements can add power to the application. When the in-line CASE gets too complex, however, its power tends to be offset by complexity. At this point, it is important to consider using the CASxx operation or a WHEN-EXSR operation set.
The form of CASE shown in Example 8.7 can provide an alternative to the standard in-line form of CASE (i.e., SELECT-WHEN-OTHER-ENDSL) logic. This form takes advantage of the SELECT-WHEN constructs while placing the process within subroutines or subprocedures.
Example 8.7: The SELECT-WHEN-EXSR-CALLP form of case.
The traditional form of CASE, using the CASxx operation, was often used in place of the technique illustrated in Example 8.7. Example 8.7 contains the much simpler CASxx structure. The logic flow of the program is the same as in Example 8.6. Example 8.8, however, allows the programmer to concentrate on the logic (i.e., choice) of the program.
Example 8.8: The subroutine CASxx operation.
.....CSRn01Factor1+++++++OpCode(ex)Factor2+++++++Result++++++++Len++DcHiLoEq C FieldA casEQ FieldB Equal C FieldA casGT FieldB Greater C FieldA casLT FieldB LessThan C FieldA casNE FieldB NotEqual C endCS
In Example 8.9, the field named FUNCT (Function) is compared to the literal 'DELETE' on line 1. The CASEQ operation is used to test for the equal condition. If the test is true (i.e., FUNCT equals 'DELETE'), the subroutine DELETERCD (Delete a Record) is performed.
Example 8.9: A basic CASE structure.
.....CSRn01Factor1+++++++OpCode(ex)Factor2+++++++Result++++++++Len++DcHiLoEq 0001 C Funct casEQ 'DELETE' DeleteRcd 0002 C endCS C*.....the program continues... 0003 Csr DeleteRcd BEGSR 0004 C Index Delete CUSTMAST 56 0005 Csr endSR
Upon completion of the subroutine DLTRCD, control returns to the END statement associated with the CASE structure (line 2 in Example 8.9). The next successive operation is performed as the program continues.
As mentioned earlier, CASE is the preferred control structure for choice constructs. Successive CASE structures are easy to read and understand. They support top-down program design by allowing the programmer to concentrate on the logic of the program (i.e., the logic modules) until the detail (i.e., the function modules) must be written. See Figure 8.13, for example, if the design of a routine calls for the type of code shown in Figure 8.12.
PROMPT the workstation operator for the FUNCTION request. READ the Operator's RESPONSE. PARSE the Operator's RESPONSE. BUILD the requested FUNCTION. IF FUNCTION equals 'DELETE' then Perform the DELETE-RECORD routine. ELSE, IF FUNCTION equals 'UPDATE' then Perform the UPDATE-RECORD routine. ELSE, IF FUNCTION equals 'ADDNEW' then Perform the ADD-RECORD routine. ELSE, IF FUNCTION equals 'SEARCH' then Perform the SEARCH routine. ELSE, IF FUNCTION equals 'EXIT' then Perform the END-PROGRAM routine. ELSE, perform the DEFAULT handler.
The RPG code that supports the design shown in Figure 8.12 is featured in Figure 8.13.
.....CSRn01..............OpCode(ex)Extended-factor2+++++++++++++++++++++++++++++ .....CSRn01Factor1+++++++OpCode(ex)Factor2+++++++Result++++++++Len++DcHiLoEq.... 0001 C Dou Funct = 'EXIT' * Prompt the workstation operator for a response. 0002 C Exsr Prompt * Parse (interpret) the Operator's response. 0003 C EXSR Parse * Finish up the PARSE by converting the request to FUNCT. 0004 C EXSR BuildFunct ** Select the subroutine when the relationship is met. 0005 C SELECT 0006 C When Funct = 'DELETE' 0007 C CallP DeleteRcd 0008 C When Funct = 'UPDATE' 0009 C CallP UpdateRcd 0010 C When Funct = 'ADDNEW' 0011 C CallP AddRcd 0012 C When Funct = 'SEARCH' 0013 C CallP SearchFile 0014 C When Funct = 'EXIT' 0015 C CallP EndProc 0016 C Other 0017 C Exsr DefaultRtn 0018 C endSL 0019 C endDo
As shown in Figure 8.13, the CASE structure makes this logic control module easy to read and comprehend. On the other hand, if an IF-THEN-ELSE structure is used, it could lead to a much more complex module.
Upon entry into the CASE structure, the relationship between the field FUNCT and the constant 'DELETE' is performed. If the relationship is true, the subroutine DLTRCD is performed. Upon completion of the subroutine DLTRCD, control passes to the END statement associated with the CASE structure.
If the relationship test on line 6 is false, control passes to the WHEN operation on line 6. If that relationship test is true, the subroutine UPDRCD is performed. Upon completion of the subroutine, control passes to the CASE structure ENDSL statement on line 18.
This process is repeated for each CASE structure in this CASE group. If none of the CASE comparisons are true, the "catch all" OTHER (otherwise) operation on line 16 performs the subroutine DFTRTN.
The CABxx (Compare and Branch) operation is unique to the RPG language. It differs from the CASxx operation in that the CASxx operation performs a subroutine and returns to the same point in the program. The CABxx operation branches to a label and does not return.
The CABxx operation supports the complete set of Boolean operators listed in Table 8.3. When the relationship test is true, a branch to the label specified in the result field is performed. When the relationship test is false, the program continues with the next successive instruction following the CABxx operation. If resulting indicators are specified, they are set on accordingly—regardless of the Boolean operator used with the operation.
Other RPG operations are required to provide a target for the CABxx operation. The TAG and ENDSR operation provide this function. Table 8.4 lists the RPG operations that support branching.
Compare and branch.
Go to (i.e., branch to) a label identified by a TAG or ENDSR operation.
End subroutine. Factor 1 can contain a label that can be used as the target of a CABxx or GOTO operation.
Label. Factor 1 contains a label that can be used as the target of a CABxx or GOTO operation.
Iterate a DO loop. Branch to the top of the DO loop for the next iteration.
Exit a DO loop. Branch to the corresponding ENDDO statement of a DO loop.
Exit subroutine. Branch to the ENDSR statement of the current subroutine.
The CABxx operation should be used primarily as an escape clause in order to branch to an exit routine or to the end of a subroutine or program. Never use CABxx or GOTO to exit a subroutine. Branching to a label on the ENDSR operation is acceptable, however.
The GOTO operation should be avoided as much as possible. Actually, many programming shops have standards and conventions that prohibit the use of GOTO. The GOTO operation is an unconditional branch to another location of the RPG program.
The ENDSR and TAG operations are declarative operations that identify a label to the RPG program. A label is the target of a CABxx or GOTO operation. The content of factor 1 is used as the label of the TAG operation.
The ITER (iterate) operation causes control of a DO loop (DO, DOW, or DOU) to be transferred to the top of the DO loop. The next iteration of the DO loop is evoked. Condition the ITER operation, when necessary, with an IF statement.
The LEAVE operation causes control of a DO loop (DO, DOW, or DOU) to be terminated. In other words, the program branches to the corresponding ENDDO statement. This operation can be considered an "Exit DO Loop" operation. Condition the LEAVE operation, when necessary, with an IF statement.
The LEAVESR operation causes a branch to the ENDSR operation for the current subroutine. This, in turn, causes the subroutine to return.