Structured Programming [ HP COBOL II/XL Programmer's Guide ] MPE/iX 5.0 Documentation
HP COBOL II/XL Programmer's Guide
Structured Programming
Structured programming makes your program easier to design, code, read,
and maintain. It is loosely defined as programming that stresses clear
top-down design:
* A complex problem is broken into functionally cohesive modules
that perform simple tasks.
* The structure and control flow of each module reflect the
programmer's approach to the problem.
* Control flows from top to bottom (it is not transferred from one
module to the middle of another module).
The COBOL'85 features that support and encourage structured programming
are listed below, by division. These are ANSI85 features. COBOL74 does
not have them. If you use them in your program, you must invoke the HP
COBOL II/XL compiler through its ANSI85 entry point.
Division ANSI85 Structured Programming Feature
Not part of a division END PROGRAM header
IDENTIFICATION DIVISION COMMON clause
DATA DIVISION GLOBAL data items and files
PROCEDURE DIVISION CONTINUE statement
EVALUATE statement
Explicit scope terminators
NOT phrases
PERFORM statement enhancements
USE GLOBAL AFTER ERROR PROCEDURE ON
statement
This section explains the following:
* ANSI85 structured programming features, by division.
* When to use nested programs and GLOBAL data.
NOTE The SPECIAL-NAMES paragraph (in the ENVIRONMENT DIVISION) cannot
appear in nested programs. All items in the SPECIAL-NAMES
paragraph are implicitly GLOBAL.
END PROGRAM Header
The END PROGRAM header ends a COBOL source program explicitly, whereas
the absence of additional source lines ends a program implicitly. When a
single source file contains more than one COBOL program, all but the last
unnested program must end explicitly, with an END PROGRAM header.
When COBOL programs are nested, their hierarchy is described by the
sequence of PROGRAM-ID paragraph/END PROGRAM header pairs. A PROGRAM-ID
paragraph and END PROGRAM header are a pair if they specify the same
program name.
Separately compiled programs within a run unit must have unique names.
Within a single separately compiled program, nested programs must have
unique names. (Nested programs are not considered to be separately
compiled.)
NOTE The HP extension ID DIVISION is not supported for applications that
use nested or concatenated programs. Use IDENTIFICATION DIVISION
instead.
Example.
IDENTIFICATION DIVISION.
PROGRAM-ID. A.
PROCEDURE DIVISION.
BEGIN-A.
DISPLAY "A IS THE OUTERMOST PROGRAM".
CALL "B".
CALL "D".
CALL "E".
IDENTIFICATION DIVISION.
PROGRAM-ID. B.
PROCEDURE DIVISION.
BEGIN-B.
DISPLAY "B IS NESTED WITHIN A".
CALL "C".
IDENTIFICATION DIVISION.
PROGRAM-ID. C.
PROCEDURE DIVISION.
BEGIN-C.
DISPLAY "C IS NESTED WITHIN B".
END PROGRAM C.
END PROGRAM B.
IDENTIFICATION DIVISION.
PROGRAM-ID. D.
PROCEDURE DIVISION.
BEGIN-D.
DISPLAY "D IS NESTED WITHIN A".
END PROGRAM D.
END PROGRAM A.
IDENTIFICATION DIVISION.
PROGRAM-ID. E.
PROCEDURE DIVISION.
BEGIN-E.
DISPLAY "E IS A CONCATENATED PROGRAM".
In the preceding example, the PROGRAM-ID paragraph/END PROGRAM header
pairs describe this nesting hierarchy:
* Program A is the parent of programs B and D. (B and D are
siblings).
* Program A is the grandparent of program C. (C is a child of
program B.)
* Program E is a concatenated program. That is, it is in the same
source file as A, B, C, and D, but is not nested within any of
them. It is considered to be a separately compiled program. (It
does not need an END PROGRAM header, because it is the last
unnested program in the source file.)
The relationship between these programs is shown graphically below:
By default, a program can only call its children and separately compiled
programs. It cannot call its siblings, its grandchildren, or their
descendants. (In the preceding example, program A can call B, D, and E,
but not C.) The COMMON clause allows exceptions to this rule.
IDENTIFICATION DIVISION: COMMON Clause
The COMMON clause allows a nested program to be called by its siblings
and their descendants, as well as its parent. (By default, it can only
be called by its parent.) The COMMON clause does not allow recursion;
that is, the common program cannot be called by its descendants or
itself.
See "Call Rules" in Chapter 4 for an example of the COMMON clause.
DATA DIVISION: GLOBAL Data Items and Files
GLOBAL data items and files can be accessed from any program nested
within the program that declares it (that is, all of its descendants).
The GLOBAL clause can appear only on 01 level data items, or on an FD
level indicator. Items subordinate to a GLOBAL data item or file are
also GLOBAL. GLOBAL items cannot be declared in the LINKAGE SECTION.
Example.
01 GLOBAL-DATA IS GLOBAL.
05 ITEM1 PICTURE XX.
05 ITEM2 PICTURE 99.
When one program contains another program, the two programs can use the
same data item names (in different DATA DIVISIONs). Unless all of these
items are EXTERNAL, they refer to distinct data items. When the compiler
encounters such a name in the PROCEDURE DIVISION, it assumes that it
applies to the first data item it finds that meets the qualifications.
For example, in the following program, a GLOBAL data item, ITEM-A, is
declared and displayed in the program OUTER. The program OUTER directly
contains the program NESTED-1. When NESTED-1 displays ITEM-A, it is
referencing the ITEM-A declared in OUTER.
However, NESTED-2, a program directly contained by NESTED-1, declares
another ITEM-A. When NESTED-2 displays ITEM-A, it is referencing the most
local ITEM-A (the one it has declared itself). (If NESTED-2 contained
nested programs, it might be desirable for it to declare its own ITEM-A
to be GLOBAL, so that it would be available to its nested programs.)
The compiler first tries to resolve the reference to a data item in the
current program. If it does not find it, it searches for GLOBAL items in
the enclosing program(s).
Example.
IDENTIFICATION DIVISION.
PROGRAM-ID. OUTER.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 ITEM-A IS GLOBAL PICTURE X(20) VALUE "Global item in OUTER".
PROCEDURE DIVISION.
BEGIN.
DISPLAY ITEM-A.
CALL "NESTED-1".
IDENTIFICATION DIVISION.
PROGRAM-ID. NESTED-1.
PROCEDURE DIVISION.
BEGIN.
DISPLAY ITEM-A.
CALL "NESTED-2".
IDENTIFICATION DIVISION.
PROGRAM-ID. NESTED-2.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 ITEM-A PICTURE X(23) VALUE "Local item in NESTED-2".
PROCEDURE DIVISION.
BEGIN.
DISPLAY ITEM-A.
END PROGRAM NESTED-2.
END PROGRAM NESTED-1.
END PROGRAM OUTER.
The above program displays the following:
Global item in OUTER.
Global item in OUTER.
Local item in NESTED-2
A data item or file can be declared both GLOBAL and EXTERNAL, in which
case it is accessible to all the nested programs with a single
declaration and to all the separately compiled programs that declare it
EXTERNAL.
PROCEDURE DIVISION
The PROCEDURE DIVISION has the following ANSI85 structured programming
features:
* CONTINUE statement.
* EVALUATE statement.
* Explicit scope terminators.
* NOT phrases.
* PERFORM statement enhancements.
* USE GLOBAL AFTER ERROR PROCEDURE ON statement.
CONTINUE Statement.
The CONTINUE statement is a nonexecutable substitute for a conditional or
imperative statement or for the keyword EXIT in an EXIT paragraph.
Example.
IF A < B THEN
IF A < C THEN
CONTINUE
ELSE
MOVE ZERO TO A
END-IF
ADD B TO C.
SUBTRACT C FROM D.
The CONTINUE statement allows control to go to the ADD statement if A is
less than C.
EVALUATE Statement.
The EVALUATE statement is a multicondition, multibranch statement. It
evaluates sets of conditions. The first time all the conditions in a set
are true, it executes the associated group of statements. (Each
condition arises from the comparison of a subject with an object. Refer
to the HP COBOL II/XL Reference Manual for details.)
Example 1.
EVALUATE HOURS-WORKED ALSO EXEMPT
WHEN 0 ALSO ANY PERFORM NO-PAY
WHEN 1 THRU 40 ALSO ANY PERFORM REG-PAY
WHEN 41 THRU 80 ALSO "N" PERFORM OVERTIME-PAY
WHEN 41 THRU 80 ALSO "Y" PERFORM REG-PAY
WHEN OTHER PERFORM PAY-ERROR
END EVALUATE
The sets of conditions in the above EVALUATE statement are:
1. HOURS-WORKED is 0 and EXEMPT is any value.
2. HOURS-WORKED is a number from 1 through 40 and EXEMPT is any
value.
3. HOURS-WORKED is a number from 41 through 80 and EXEMPT contains
"N".
4. HOURS-WORKED is a number from 41 through 80 and EXEMPT contains
"Y".
If condition 1 is true, NO-PAY is performed. If condition 1 is false and
condition 2 is true, REG-PAY is performed. If conditions 1 and 2 are
false and condition 3 is true, OVERTIME-PAY is performed. If conditions
1, 2, and 3 are false and condition 4 is true, REG-PAY is performed. If
conditions 1, 2, 3, and 4 are false, PAY-ERROR is performed.
You can always write an EVALUATE statement that is equivalent to a nested
IF statement, but you cannot always write a nested IF statement that is
equivalent to an EVALUATE statement. This is because there is a limit to
the depth that IFs can be nested, but an EVALUATE statement can specify
any number of conditions.
Example 2.
The following example is equivalent to the example above[REV BEG] if
there is a period after END-EVALUATE. See Example 3 below.[REV END] It
uses IF-THEN-ELSE statements instead of an EVALUATE statement.
IF HOURS-WORKED = 0
PERFORM NO-PAY
ELSE IF HOURS-WORKED >= 1 AND <= 40
PERFORM REG-PAY
ELSE IF EXEMPT ='N'
IF HOURS-WORKED >= 41 AND <= 80
PERFORM OVERTIME-PAY
ELSE PERFORM PAY-ERROR
ELSE IF EXEMPT = 'Y'
IF HOURS-WORKED >= 41 AND <= 80
PERFORM REG-PAY
ELSE PERFORM PAY-ERROR
ELSE PERFORM PAY-ERROR.
[REV BEG]
Example 3.
The following example is also equivalent to the example above, but it
uses the structured form of the IF-THEN-ELSE statement with the END-IF
scope terminator:
IF HOURS-WORKED = 0
PERFORM NO-PAY
ELSE
IF HOURS-WORKED >= 1 AND <= 40
PERFORM REG-PAY
ELSE
IF EXEMPT ='N'
IF HOURS-WORKED >= 41 AND <= 80
PERFORM OVERTIME-PAY
ELSE
PERFORM PAY-ERROR
END-IF
ELSE
IF EXEMPT = 'Y'
IF HOURS-WORKED >= 41 AND <= 80
PERFORM REG-PAY
ELSE
PERFORM PAY-ERROR
END-IF
ELSE
PERFORM PAY-ERROR
END-IF
END-IF
END-IF
END-IF
[REV END]
HP COBOL II/XL evaluates the clauses in an EVALUATE statement in order.
For fastest execution, order the clauses from most frequent value to
least frequent value.
Explicit Scope Terminators.
An explicit scope terminator is a keyword, END-verb, that terminates the
scope of the last instance of the keyword verb. The explicit scope
terminators are listed in the following table:
Table 3-1. The Scope Terminators
END-ACCEPT
END-ADD
END-CALL
END-COMPUTE
END-DELETE
END-DIVIDE
END-EVALUATE
END-IF
END-MULTIPLY
END-PERFORM
END-READ
END-RETURN
END-REWRITE
END-SEARCH
END-START
END-STRING
END-SUBTRACT
END-UNSTRING
END-WRITE
Explicit scope terminators help to eliminate logic errors caused by
misplaced periods. With explicit scope terminators, periods are required
only to terminate paragraphs in the PROCEDURE DIVISION.
Example 1.
The following example shows the END-IF scope terminator. The first
END-IF terminates the scope of IF PROCESS-2-OK. The second END-IF
terminates the scope of IF PROCESS-1-OK.
IF PROCESS-1-OK THEN
IF PROCESS-2-OK THEN
MOVE 2 TO PROCESS-DATA-FLAG
ELSE
MOVE 1 TO PROCESS-DATA-FLAG
END-IF
PERFORM PROCESS-DATA
ELSE
PERFORM PROCESS-1-ERROR-CHECK
END-IF
A conditional statement used with an explicit scope terminator is called
a delimited scope statement. Unlike an ordinary conditional statement, a
delimited scope statement is legal wherever an imperative statement is
legal.
Example 2.
READ FILE-IN AT END
ADD A TO B ON SIZE ERROR
PERFORM OVERFLOW-ROUTINE
END-ADD
MOVE SPACES TO REC-IN.
The ADD statement with the ON SIZE ERROR phrase would be a conditional
statement if not for the END-ADD, which terminates its scope and makes it
a delimited scope statement. The ADD statement and the imperative
statement MOVE make up the statement group following the conditional
phrase AT END. Ordinary conditional statements are illegal in the
statement group following a conditional phrase.
NOT Phrases.
A NOT phrase specifies a set of statements to be executed if an exception
condition does not occur. The NOT phrases are listed below:
NOT AT END
NOT AT END-OF-PAGE
NOT INVALID KEY
NOT ON EXCEPTION
NOT ON INPUT ERROR
NOT ON OVERFLOW
NOT ON SIZE ERROR
Using NOT phrases can make code more readable and sometimes more
efficient.
Example.
The following are functionally equivalent:
READ IN-FILE READ IN-FILE
AT END MOVE 'YES' TO EOF. AT END MOVE 'YES' TO EOF
IF EOF <> 'YES' THEN NOT AT END ADD 1 TO IN-CNT.
ADD 1 TO IN-CNT.
The statements on the left perform two tests for every record read. The
statement on the right performs one test for every record read. In this
case, the NOT phrase makes the code more efficient as well as more
readable.
NOT phrases used with I-O verbs execute only after a successful condition
occurs. In the preceding example on the right, "ADD 1 TO IN-CNT" is not
executed if a logic error exists.
PERFORM Statement Enhancements.
The enhanced PERFORM statement can contain a list of statements rather
than only procedure names if it ends with an END-PERFORM. This form of
the PERFORM statement is called an in-line PERFORM statement.
Example 1.
The following is an in-line PERFORM statement:
PERFORM 10 TIMES
ADD A TO B
ADD 1 TO A
END-PERFORM
Example 2.
The in-line PERFORM statement can significantly reduce code
fragmentation. It eliminates the need for short paragraphs whose only
functions are to perform other paragraphs. The following two code
fragments are equivalent:
PERFORM A100-CALC-A A-CNT TIMES. PERFORM A-CNT TIMES
: ADD C TO A (SUBA)
A100-CALC-A. ADD 1 TO SUBA
ADD C TO A (SUBA). END-PERFORM.
ADD 1 TO SUBA.
:
The PERFORM on the left executes a separate paragraph in a different
location in the program. The inline PERFORM on the right is functionally
equivalent. By embedding the statements within the PERFORM, the program
is much easier to read.
The enhanced PERFORM statement can also specify whether the UNTIL
condition is to be tested before or after the statements or paragraphs
have been executed.
Example 3.
The following PERFORM statement tests EOF-FLAG and then performs
READ-LOOP if EOF-FLAG is false:
PERFORM READ-LOOP
WITH TEST BEFORE BEFORE is the default.
UNTIL EOF-FLAG
The following PERFORM statement performs READ-LOOP and then tests
EOF-FLAG. If EOF-FLAG is false, it performs READ-LOOP again:
PERFORM READ-LOOP
WITH TEST AFTER
UNTIL EOF-FLAG
Example 4.
In-line PERFORM statements can be nested. Nested in-line PERFORM
statements can make your program more readable and less fragmented.
The following shows an example without nested in-line PERFORM statements:
PERFORM PROC-NAME-1
[REV BEG]
VARYING DEPARTMENT FROM FIRST-DEPT BY 1 UNTIL LAST-DEPARTMENT
AFTER HOURS-PER-EMPLOYEE FROM FIRST-EMP BY 1 UNTIL LAST-EMPLOYEE.
[REV END]
STOP RUN.
:
PROC-NAME-1.
:
The following shows an example with nested in-line PERFORM statements:
[REV BEG]
PERFORM VARYING DEPARTMENT FROM FIRST-DEPT BY 1 UNTIL LAST-DEPARTMENT
[REV END]
{statement-group-1}
PERFORM VARYING HOURS-PER-EMPLOYEE
[REV BEG]
FROM FIRST-EMP BY 1 UNTIL LAST-EMPLOYEE
[REV END]
{statement-group-2}
END-PERFORM
{statement-group-3}
END-PERFORM
With only statement-group-2, the second example is functionally
equivalent to the first. With statement-group-1 and statement-group-3,
the second example is more powerful than the first.
USE GLOBAL AFTER ERROR PROCEDURE ON Statement.
The USE GLOBAL AFTER ERROR PROCEDURE ON statement makes the scope of a
USE procedure match the scope of the program that declares the USE
procedure. That is, the statement applies to the program that contains
it and to all programs directly or indirectly contained within that
program.
A USE GLOBAL AFTER ERROR PROCEDURE ON statement specifies either a file
open mode or the name of a GLOBAL file.
Using a File Open Mode.
An example of the first case is the following statement:
USE GLOBAL AFTER ERROR PROCEDURE ON INPUT.
If the program containing this statement, or any program contained in
that program, encounters an error while reading any file that is open for
input, the USE procedure is invoked. Thus, file error handling is
standardized in the outermost program, even if the errors occur on files
that are local to inner programs and invisible to the outermost program.
(In the example in the next section, "When to Use Nested Programs and
GLOBAL Data," only the inner programs invoke the GLOBAL USE AFTER ERROR
PROCEDURE ON INPUT statement in the outer program, because only they have
files that are open for input.)
Using a GLOBAL File.
An example of the second case is the following statement, where FILE-A is
a GLOBAL file:
USE GLOBAL AFTER ERROR PROCEDURE ON FILE-A
If a program containing this statement, or any program contained in that
program, encounters an error while accessing FILE-A in any way, the USE
procedure is invoked. Thus, the error handling for the GLOBAL file
FILE-A need only be coded once, even though errors on FILE-A may be
encountered in other (contained) programs.
If more than one USE procedure applies to a situation, the first one
found is executed. The search for this "first found" USE procedure
begins in the program where the situation arises and proceeds outward
through the enclosing programs.
NOTE An EXIT PROGRAM statement executed directly or indirectly within a
GLOBAL USE procedure has undefined results.
When to Use Nested Programs and GLOBAL Data
The structured programming features described in the previous section,
"Structured Programming," are part of ANSI85 COBOL. They allow you to
divide your application into programs whose nesting hierarchy and data
organization express and document your programming approach. This
clarifies the logical structure of your program, making it easier to
understand, debug, and maintain.
HP COBOL II/XL has always had divisions, paragraphs, sections, and the
PERFORM statement to organize code. However, the relationship between
data and code in complex COBOL programs has been obscured by the size of
the DATA DIVISION and the complexity of the code. Nested programs offer
a solution to this problem, a way to associate data with the code that
uses it. Data that is used by many programs in an application can be
declared GLOBAL in the DATA DIVISION of the outermost program. Data that
is used by one program can be declared in that program's DATA DIVISION
only.
Nested programs are also appropriate for applications where complex tasks
are composed of smaller tasks. The complex task can be initiated by the
outer program and the smaller tasks can be performed by programs nested
within it. And the smaller tasks can be broken down into relatively
simple paragraphs and sections. The nesting structure helps document the
data and logic dependencies of the program as a whole.
A good way to decide whether to break an application down into nested
programs (instead of just paragraphs or sections) is to first decide on
the clearest way to organize the data. If a task is fairly complex and
requires a set of data items and files that other sections of the program
will not need, then the task is a candidate for nested programming.
Example - A Payroll Application.
The following simplified payroll program illustrates the approach
discussed above, using nested programs, GLOBAL data items and files, and
GLOBAL USE procedures.
The nested programs break the payroll application into logical units with
distinct functionality. Note that one of the nested programs is declared
COMMON. In this simple example, it does not need to be COMMON, but in a
realistic payroll implementation, this would be appropriate (see the
comments in the program below).
The payroll program contains both local and GLOBAL files. Local files
are used when only one program needs to access their data; GLOBAL files,
when all programs do.
A GLOBAL USE procedure is declared ON INPUT. Only local files are opened
for input, so this USE procedure is only invoked by local files. Because
this USE procedure is GLOBAL, this code only needs to appear in one
place.
The comments in the program itself explain the logic and nesting
structure of the program in more detail.
***************************
*PROGRAM-ID. PAYROLL.
* Payroll declares and opens two global files CURR-PAY-REC and
* EMPLOYEE-INFO. For each record in CURR-PAY-REC it calls
* GET-CURR-GROSS and GET-CURR-DEDUCTIONS. It also updates the
* year-to-date payroll fields in EMPLOYEE-INFO.
* It declares a GLOBAL use procedure for INPUT mode, which will
* be used when local files with tax and pay scale tables
* (opened only in input mode) encounter errors.
*
* *****************************
* * PROGRAM-ID. GET-CURR-GROSS.
* * {Calculates current gross, using a local file PAY-FILE
* * which contains the pay rates.}
* * END PROGRAM GET-CURR-GROSS.
* *****************************
*
* *****************************
* * PROGRAM-ID. GET-CURR-DEDUCTIONS.
* * {Calculates current deductions, using a local file TAX-FILE.
* * For simplicity only social security tax is calculated. The
* * complex calculations of a realistic payroll program could
* * be carried out with a set of local data declarations.}
* * END PROGRAM GET-CURR-DEDUCTIONS.
* *****************************
*
* *****************************
* * PROGRAM-ID. HASHED-READ-ON-EMPLOYEE-FILE IS COMMON.
* * Passed a social security number, this routine makes a
* * relative key and executes either a read or rewrite.
* * This program is COMMON. It is callable by any program
* * nested within PAYROLL. (Only the outermost program calls
* * it here but a realistic payroll program might call it
* * to update yearly vacation, sick leave, tax status etc.)
* * END PROGRAM HASHED-READ-ON-EMPLOYEE-FILE.
* *****************************
*
* END PROGRAM PAYROLL.
*****************************
$PAGE "PAYROLL"
IDENTIFICATION DIVISION.
PROGRAM-ID. PAYROLL.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT CURR-PAY-FILE ASSIGN TO "CURRPAY"
ORGANIZATION IS SEQUENTIAL.
SELECT EMPLOYEE-INFO ASSIGN TO "EMPINFO"
ORGANIZATION IS RELATIVE
ACCESS IS RANDOM
RELATIVE KEY IS EMP-INFO-KEY
FILE STATUS IS FILE-STATUS.
DATA DIVISION.
FILE SECTION.
* When the FD is GLOBAL, all subordinate records are also GLOBAL.
FD CURR-PAY-FILE IS GLOBAL.
01 CURR-PAY-REC.
05 CURR-NAME PICTURE X(20).
05 CURR-SS-NO PICTURE X(9).
05 CURR-HOURS PICTURE 999.
05 CURR-GROSS PICTURE $$$,$$$.99.
05 CURR-DEDUCTIONS PICTURE $$$,$$$.99.
FD EMPLOYEE-INFO IS GLOBAL.
01 EMPLOYEE-REC.
05 EMP-SS-NO PICTURE X(9).
05 EMP-JOB-DESCRIPTOR PICTURE 99.
05 EMP-YEARLY-GROSS PICTURE 9(6)V99
USAGE PACKED-DECIMAL.
05 EMP-YEARLY-DEDUCTIONS PICTURE 9(6)V99
USAGE PACKED-DECIMAL.
WORKING-STORAGE SECTION.
01 EMP-INFO IS GLOBAL.
05 UNIQUE-KEY PIC 999.
88 NO-UNIQUE-KEY VALUE 999.
01 EMP-INFO-KEY REDEFINES EMP-INFO IS GLOBAL PIC 9(3).
01 FILE-STATUS IS GLOBAL PIC XX.
01 FILE-NAME IS GLOBAL PIC X(10) VALUE SPACES.
PROCEDURE DIVISION.
DECLARATIVES.
GLOBAL-USE-PROC SECTION.
USE GLOBAL AFTER STANDARD ERROR PROCEDURE ON INPUT.
GLOBAL-USE.
* This will be executed when local files TAX-RATES and
* PAY-RATES encounter an error.
DISPLAY FILE-NAME, " Status is ", FILE-STATUS.
END DECLARATIVES.
PROCESS-PAYROLL SECTION.
OPEN-FILES.
OPEN I-O CURR-PAY-FILE
OPEN I-O EMPLOYEE-INFO.
READ-PAY-FILE.
READ CURR-PAY-FILE
AT END
CLOSE CURR-PAY-FILE
NOT AT END
CALL "HASHED-READ-ON-EMPLOYEE-FILE" USING CURR-SS-NO
CALL "GET-CURR-GROSS"
CALL "GET-CURR-DEDUCTIONS"
DISPLAY CURR-NAME," ", CURR-SS-NO," ", CURR-HOURS,
" ",CURR-GROSS," ", CURR-DEDUCTIONS
WRITE CURR-PAY-REC
CALL "HASHED-REWRITE-ON-EMPLOYEE-FILE" USING CURR-SS-NO
DISPLAY EMP-SS-NO," ",EMP-JOB-DESCRIPTOR," ",
EMP-YEARLY-GROSS," ",EMP-YEARLY-DEDUCTIONS
GO READ-PAY-FILE
END-READ
CLOSE EMPLOYEE-INFO
STOP RUN.
$PAGE "GET-CURR-GROSS"
$CONTROL DYNAMIC
IDENTIFICATION DIVISION.
PROGRAM-ID. GET-CURR-GROSS.
* USE EMP-JOB-DESCRIPTOR TO INDEX TABLE-OF-PAY TO GET WAGE RATE
* AND CALCULATE CURRENT GROSS SALARY.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT PAY-RATES ASSIGN TO "PAYRATES"
FILE STATUS IS FILE-STATUS.
DATA DIVISION.
FILE SECTION.
* PAY-RATES is LOCAL to this program.
FD PAY-RATES.
01 TABLE-OF-PAY.
05 RATES OCCURS 99 TIMES.
10 HOURLY-PAY PICTURE 9999V99 USAGE PACKED-DECIMAL.
10 REDEF-HOURLY REDEFINES HOURLY-PAY.
15 SALARY PICTURE 9999V99 USAGE PACKED-DECIMAL.
WORKING-STORAGE SECTION.
01 RATE PICTURE 9999V99 USAGE PACKED-DECIMAL.
01 GROSS PICTURE 9(6)V99 USAGE PACKED-DECIMAL.
01 JOB-CLASS PICTURE 99.
88 NON-EXEMPT VALUE 0 THRU 50.
88 EXEMPT VALUE 51 THRU 99.
01 OVERTIME PICTURE 999.
88 WORKED-OVERTIME VALUE 41 THRU 100.
PROCEDURE DIVISION.
OPEN-LOCAL-FILE.
MOVE "PAYRATES" TO FILE-NAME.
OPEN INPUT PAY-RATES
READ PAY-RATES.
UPDATE-GROSS-PAY.
MOVE EMP-JOB-DESCRIPTOR TO JOB-CLASS
EVALUATE EXEMPT
WHEN TRUE PERFORM SALARIED-LABOR
WHEN FALSE PERFORM HOURLY-LABOR
END-EVALUATE
COMPUTE EMP-YEARLY-GROSS = EMP-YEARLY-GROSS + GROSS
MOVE GROSS TO CURR-GROSS
CLOSE-LOCAL-FILE.
CLOSE PAY-RATES.
EXIT PROGRAM.
HOURLY-LABOR.
MOVE HOURLY-PAY (EMP-JOB-DESCRIPTOR) TO RATE
MOVE CURR-HOURS TO OVERTIME
EVALUATE WORKED-OVERTIME
WHEN FALSE
COMPUTE GROSS = CURR-HOURS * RATE
WHEN TRUE
COMPUTE GROSS = 40 * RATE +
(CURR-HOURS - 40 * RATE * 1.5)
END-EVALUATE.
SALARIED-LABOR.
MOVE SALARY (EMP-JOB-DESCRIPTOR) TO GROSS.
END PROGRAM GET-CURR-GROSS.
$PAGE "GET-CURR-DEDUCTIONS"
IDENTIFICATION DIVISION.
PROGRAM-ID. GET-CURR-DEDUCTIONS.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT TAX-RATES ASSIGN TO "TAXRATES"
FILE STATUS IS FILE-STATUS.
DATA DIVISION.
FILE SECTION.
* TAX-RATES is LOCAL to this program.
* For simplicity, only social security tax is calculated.
FD TAX-RATES.
01 TABLE-OF-TAXES.
05 FICA-TAX-RATE PICTURE 9999V999 USAGE PACKED-DECIMAL.
WORKING-STORAGE SECTION.
01 GROSS PICTURE 9(6)V99 USAGE PACKED-DECIMAL.
01 DEDUCTIONS PICTURE 9(6)V99 USAGE PACKED-DECIMAL.
PROCEDURE DIVISION.
OPEN-LOCAL-FILE.
MOVE "TAXRATES" TO FILE-NAME
OPEN INPUT TAX-RATES
READ TAX-RATES.
UPDATE-DEDUCTIONS.
MOVE CURR-GROSS TO GROSS
COMPUTE DEDUCTIONS = GROSS * FICA-TAX-RATE
COMPUTE EMP-YEARLY-DEDUCTIONS =
EMP-YEARLY-DEDUCTIONS + DEDUCTIONS
MOVE DEDUCTIONS TO CURR-DEDUCTIONS.
CLOSE-LOCAL-FILE.
CLOSE TAX-RATES.
END PROGRAM GET-CURR-DEDUCTIONS.
$PAGE "HASHED-ACCESS-ON-EMPLOYEE-FILE"
IDENTIFICATION DIVISION.
PROGRAM-ID. HASHED-READ-ON-EMPLOYEE-FILE IS COMMON.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 KEY-SWITCH PIC X.
88 SUCCESS VALUE "Y".
88 RESET-SWITCH VALUE "N".
LINKAGE SECTION.
01 SS-NO PICTURE X(9).
PROCEDURE DIVISION USING SS-NO.
BEGIN-HASHED-READ.
SET RESET-SWITCH TO TRUE
MOVE SS-NO(1:3) TO EMP-INFO-KEY
PERFORM UNTIL SUCCESS
READ EMPLOYEE-INFO
INVALID KEY ADD 1 TO UNIQUE-KEY
NOT INVALID KEY IF EMP-SS-NO = SS-NO THEN
SET SUCCESS TO TRUE
END-IF
END-READ
END-PERFORM
EXIT PROGRAM.
ENTRY "HASHED-REWRITE-ON-EMPLOYEE-FILE" USING SS-NO.
BEGIN-HASHED-REWRITE.
IF EMP-SS-NO
SS-NO THEN
DISPLAY "HASHING SCHEME REQUIRES READ BEFORE REWRITE"
ELSE
REWRITE EMPLOYEE-REC
INVALID KEY
DISPLAY "Employee-file Status is ", FILE-STATUS
NOT INVALID KEY
EXIT PROGRAM
END-IF.
END PROGRAM HASHED-READ-ON-EMPLOYEE-FILE.
END PROGRAM PAYROLL.
MPE/iX 5.0 Documentation