Académique Documents
Professionnel Documents
Culture Documents
Conditions
High/Low Values
Qualified Fields
Condition Names
Index
Ref. Modification
Continuation
Julian Dates
Reports
Control Breaks
Level Numbers
Sections
Data Types
Literals
Subscripts
Dates
Paragraphs
Tables
Delimiters
PIC Clauses
Truncation
Fields
Statements/Clauses:
77-level Fields
Go To
Release
88-level Fields
Goback
Return
Accept
If
Rewrite
Add
Initialize
Rounded
Inspect
Search
Call
Invalid Key
Set
Close
Merge
Sort
Compute
Move
Start
Copy
Multiply
Stop Run
Corresponding
Numeric Fcns
String
Date Functions
Occurs
Subtract
Delete
On Size Error
Unstring
Display
Open
Usage
Divide
Perform
Using
Evaluate
Read
Value
Exit
Read Next
Write
Exit Program
Redefines
Back to Main
Conditions
A condition is a special piece of code that allows you to instruct the computer to compare two
pieces of data. Conditions are used in IF statements and in the While/Until clauses of the
PERFORM statement
Conditions have the syntax:
data-1 operator data-2
where data-1 and data-2 can be a literal or a field. data-2 can also be a COBOL literal such as
SPACES or ZEROS.
Operator can be the traditional comparison symbols =, <, >, <=, >=. To check for inequality use
'NOT =' since not all compilers accept the symbol <>. Rarely, a compiler will not accept <= or
>=. You can use 'NOT >' and 'NOT <' instead. To comply with older versions of COBOL English
can be used (i.e. EQUALS, IS NOT EQUAL TO, etc.).
Conditions can be combined into a compound condition by using AND and OR. Unless directed
to do otherwise by grouping conditions with parenthesis COBOL will evaluate the ANDs first,
then the ORs. If the conditions also contain NOTs then those are evaluated before the ANDs.
Also see 88-level Fields.
Back to Table of Contents
Continuation
Statements can be continued over several lines without doing anything more than placing the
code on separate lines. The compiler will figure it out.
Very long alphanumeric literals can be continued on multiple lines by placing a hyphen in
column 7 of the continuation lines and placing the remainder of the literal there. This
continuation of the literal requires a beginning single quote. The literal on the previous line does
not have an ending single quote but is considered to extend to column 72.
The hyphen on the 2nd line is in column 7. The single quote on that line is in column 12 and the
literal continues from there. The ending single quote on that line is required. Note that the
portion of the literal that's on the first line does not have an ending quote. If the last 'E' is not in
column 72 then it will be assumed that all characters between that 'E' and column 72 are spaces
and will appear in the literal.
Also valid with value clauses.
Back to Table of Contents
Control Breaks
Control breaks are a feature of reports that allow for the grouping of and accumulating subtotals
for data that belong together based on the value of a field (the control field). When the value for
this field changes from one record to another the program "breaks" to do some special processing
(like printing subtotals) before it goes on with the next record. The input file must be sorted on
the control field(s).
An example of a report with a single-level control break:
04/20/1999
Page
Payroll Register
Department: Janitorial
Employee Nbr
Name
Hours
Rate
Pay
123 45 6789
111 11 1111
Ray, Marcus
Griese, Brian
40.0
50.0
2.00
2.50
80.00
125.00
90.0
205.00
Gates, Willy
...
Grand Totals:
12.0
...
1,002.5
800.00
...
9,600.00
...
258,125.00
The control break is on department. Each control group (department) has it's own headings and
footings (totals). Though it's not shown here in this example it's common for column headings to
be repeated after each control heading.
See the algorithms page for sample code.
Back to Table of Contents
Data Types
There are basically three types of data recognized by COBOL. Numeric data (both with or
without decimal places: only 0-9, the decimal point and a sign allowed), alphabetic (only the
characters A-Z) and alphanumeric (any characters). Alphabetic is rarely used.
Math can only be performed on numeric fields.
Back to Table of Contents
Dates
Dates are common data for COBOL programs and must be manipulated often. Typically dates
are stored in the Gregorian format, consisting of the familiar month, day and year. This is
generally called the 'mmddyy' format, though the 'mmddyyyy' format is becoming the new
standard (see the Y2K discussion page). While those formats are familiar to the coders and users
dates are more often stored in 'yymmdd' or 'yyyymmdd' format so that they can be sorted easily.
So-called 'calendar math', where dates are used in calculations, can be a tedious process, unless
your compiler supports the intrinsic date functions. If not, remember the following about the
Gregorian calendar:
The 'official' method of determining if a year is a leap year requires dividing the 4-digit
year by 4, 100 and 400 and looking at the remainders of those three calculations. If the
first remiander is 0 then the year is a leap year, but if the second remainder is also 0 then
the year is not a leap year, but if the third remainder is also a 0 then the year is a leap year
again. This is why 2000 is a leap year by 1900 and 2100 are not. These checks must be
nested within each other, trying to put them in a single IF will not work.
Verbs that have end-delimiters are the comparison verbs (IF, EVALUATE), input/output (READ,
WRITE, DELETE, REWRITE, ACCEPT), math (ADD, SUBTRACT, MULTIPLY, DIVIDE,
COMPUTE), processing transfer (PERFORM, CALL) and some other lesser used verbs.
When the compiler encounters a period it takes that as the end of the statement. A delimiter that
is found after a period is in error.
Back to Table of Contents
Fields
A field is what other languages call a variable. It's a place to store data. All fields must be
declared in the DATA DIVISION. A field declaration has three parts: the level number, the field
name and the PIC clause. VALUE clauses are optional.
A valid field name is from 1 to 30 characters in length; contains only the letters A-Z, the digits 09 and the hyphen; contains at least one letter; does not begin or end with a hyphen; and is not a
COBOL reserved word.
Also see Qualified Fields.
Back to Table of Contents
HIGH-VALUES/LOW-VALUES
These are special numeric literals inherent to COBOL. HIGH-VALUES is the COBOL
equivalent to infinity - no number is greater than HIGH-VALUES. Conversely, no number is less
than LOW-VALUES.
They can be used in VALUE clauses, conditions and MOVE statements but math cannot be
performed using these literals.
Back to Table of Contents
Julian Dates
Julian is a date format that's an alternative to Gregorian dates. It consists of a 3-digit day and a
year; there are no months. The days range from 1 (Jan 1st) to either 365 or 366 (Dec 31),
depending on if the year is a leap year or not. This is generally known as the 'dddyy' or 'dddyyyy'
format, even though normally the date is stored as 'yyddd' or 'yyyyddd' to ease with sorting.
Shops that make use of Julian dates will have callable routines that covert Julian to Gregorian
and back again, because humans are comfortable with Gregorian dates. Intrinsic date functions
available with newer COBOL compilers have these conversions built-in.
Julian format has two advantages. First, it's smaller, so it takes up less space. Second, it eases
with some calculations because it contains no months. For example, how many days are between
Feb 5, 1997 and Nov 28, 1999? Convert to Julian (1997036 and 1999332) a quick subtraction
gives 1026 days. Remember that 'borrowing' a year gives you 365 days.
Getting a future date or past date can also be easier with Julian. What date is 45 days before Apr
15, 1999? Convert it to Julian (1999105), subtract 45 to get 1999060) and convert back to
Gregorian (Mar 1, 1999).
INPUT-RECORD.
05 IN-EMPLOYEE-NUMBER
05 IN-EMPLOYEE-NAME.
10 IN-EMP-LAST-NAME
10 IN-EMP-FIRST-NAME
10 IN-EMP-MIDDLE
05 IN-BIRTH-DATE.
10 IN-BIRTH-DD
10 IN-BIRTH-MM
10 IN-BIRTH-YEAR.
15 IN-BIRTH-CC
15 IN-BIRTH-YY
05 IN-DEPARTMENT
PIC 9(09).
PIC X(30).
PIC X(15).
PIC X.
PIC 99.
PIC 99.
PIC 99.
PIC 99.
PIC X(05).
We have an 01-level field that is broken down into 4 fields (the 05-level fields). Two of the 05level fields are also broken down. Employee number is an elementary field because it is not
broken down into smaller fields. The employee name and birth date are group level fields
because they are broken down into smaller fields. Only elementary fields have PIC clauses.
The birth date is 8 characters long (the sum of the lengths of the elementary fields that compose
it). All 8 characters can be accessed with one name (IN-BIRTH-DATE) or one of its pieces can
be accessed by using that name instead (i.e. IN-BIRTH-MM).
A group level item 'ends' when another field with the same level number, or one with a lower
value, is encountered. For example, the list of fields within IN-BIRTH-YEAR ends when the 05level IN-DEPARTMENT is encountered. A field of level 10 would also have ended it.
All group level fields are considered to be alphanumeric.
All of these level number concepts are valid for WORKING-STORAGE also.
Also see 77-level Fields 88-level Fields.
Back to Table of Contents
Literals
Literals are specific values as opposed to fields. Alphanumeric literals are enclosed in single
quotes. In the following statements:
MOVE 3.1415927 TO WS-PI.
DISPLAY 'Enter a number: '.
3.1415927 is a numeric literal and 'Enter a number: ' is an alphanumeric literal. COBOL has
some built-in literals like ZEROES and SPACES.
Also see Continuation HIGH-VALUES/LOW-VALUES.
Back to Table of Contents
Paragraphs
A paragraph is a section of COBOL code. Paragraph names start in the 'A' margin and follow the
same naming rules that fields do. A paragraph ends when another paragraph name is
encountered. Paragraphs can be executed with the PERFORM statement.
You can think of a pargraph as the equivalent of a subroutine in other languages. There are no
arguments, all fields are thought of as global.
Also see Sections.
Back to Table of Contents
PIC Clauses
PIC (short for PICture) clauses describe the size and type of data for each field. Numeric data has
a PIC character of 9, alphanumeric data uses X and alphabetic data an A. Each 9, X or A
represents one character. Length can also be represented by a repetition factor. The PIC clauses
9999 and 9(04) both define 4-digit numbers.
The PIC character V is used to mark where a decimal point is. If you had a 8-digit numeric field
but 2 of the digits are after the decimal point, you would define it as PIC 9(06)V99. The decimal
point is implied, it is not physically there in the data. It also takes up no space. To allow for a
field to hold either positive or negative numbers precede the leftmost PIC character with an S
(PIC S999V99).
There are several output PIC characters which help with formatting data for display or print.
Numeric fields are MOVEd to fields defined with these formatting PIC characters. Fields defined
with these formatting PIC characters are considered alphanumeric. No calculations can be done
with these fields. Newer versions of COBOL allow these fields to be MOVEd to straight numeric
fields.
To print a decimal point place a '.' in the desired place in the output PIC clause (i.e. PIC 999.99).
You can place commas in output numbers also (i.e. PIC 999,999.99). In this manner the decimal
point (and commas) do take up space. These are considered insertion characters - they insert
themselves into the data. Other insertion characters are B (for a space), 0 (a zero) and / (useful in
printing dates).
There is Z, for suppressing leading zeroes. If the digit represented by a Z is a leading zero it will
print as a blank. You normally have one 9 in the PIC clause, in the one's place. All other digits
represented by Z's. Do not use Z's after the decimal point. If used with commas (i.e. PIC
ZZZ,ZZ9.99) a comma will only print if the character to its left prints, else it prints as a blank.
There are other zero suppression characters. A $ can be used just like the Z except that rightmost
leading zero will print as a $ and all zeroes to the left of that will print as spaces. So the value of
125.00 MOVEd to a PIC $$$,$$9.99 will print as ' $125.00'. This behavior of the $ is called
'floating'. An * will work the same way (for check protection) but all * print, not just the one to
the left of the most significant digit. When either the floating $ or the * is used in conjunction
with commas the comma will only print as a comma if the character to its left prints as a digit.
Depending on the situation it will otherwise print as a blank, $ or *.
For sign control you can use + or - as an output PIC character. A + will print + for positive
numbers and - for negative numbers. A - will print a - for negative numbers and a blank for
positive numbers. Either can be repeated to suppress leading zeroes (like the $) and can 'float'
(also like the $). Alternatively, a + or - can be placed to the right of the number.
For accounting purposes the PIC characters 'DB' and 'CR' can also be used (i.e. PIC $$$,$
$9.99DB). The DB or CR will only show if the value is negative. If positive they will print
blanks.
Also see Blank When Zero Truncation.
Back to Table of Contents
Qualified Fields
It is legal in COBOL for different fields to have the same name. These fields cannot be 01-level
fields and cannot be part of the same group-level field.
When referencing one of these fields the compiler requires the field to be qualified, meaning its
group-level field must be specified. If both INPUT-RECORD and OUTPUT-RECORD contained
a field named PAY-RATE then in code you cannot simply reference PAY-RATE, it would have to
either be PAY-RATE OF INPUT-RECORD or PAY-RATE OF OUTPUT-RECORD.
Back to Table of Contents
Reference Modification
Reference modification allows for the referencing of a portion of a field without having to make
it a group-level field and defining each portion of the field that will be accessed.
If you wanted to check the value of the 4th through 6th characters of a field to see if they were
equal to ABC you can code:
IF WS-FIELD (4:3) = 'ABC'
The first number in the parenthesis represents the start position in the field and the second
number represents the length. Both values have to be specified. COBOL treats all such
references as alphanumeric.
Since this is not a self-documenting feature it should not be used carelessly.
Back to Table of Contents
Reports
A report is simply a formatted representation of data, suitable for being printed on paper
(hardcopy). Reports generically look like:
04/20/1999
Employee Nbr
123 45 6789
456 78 9123
...
Totals:
Page
Hours
Rate
40.0
12.0
...
2.00
800.00
...
1,002.5
1
Pay
80.00
9,600.00
...
258,125.00
The first two lines are page headings, which will appear on every page. The next printed line
(following the blank line) is column headings. It's common for column heading lines to be
printed on every page. Next come the detail lines - typically one per record. At the end of the
report will be a total line (if you are totalling anything). Note that the first detail line is the 6th
line printed on a page (must count the blank lines also).
There are other types of lines that can appear on reports. Sometimes there are page footings
(printed on the bottom of each page). There can also be report headings and report footings (only
printed at the top and bottom of the report as opposed to each page).
Note the formatting of the data. There are commas and leading zeroes are suppressed on page
numbers and monetary figures. The date has slashes. Always make reports as easy to read as
possible.
See the algorithms page for sample code.
Also see PIC clauses.
Back to Table of Contents
Sections
A section is a group of paragraphs. The section name must begin in the 'A' margin and be
followed by the word 'SECTION'. Naming standards for sections are the same as those for
paragraphs. A section ends when a new one begins.
A section can be PERFORMed in the same manner a paragraph is PERFORMed. The
PERFORM only uses the section name, there is no reference to it actually being a section instead
of a paragraph.
Back to Table of Contents
Subscripts and Indexes
Subscripts and indexes are the two tools used to reference individual elements of a table. A
subscript is a working-storage field defined separately from the table and is completely available
to the programmer. An index is created automatically by the system if it is directed to do so and
only has limited availability to the programmer.
An index cannot be part of a calculation, cannot be MOVEd to another field or cannot receive
another field from a MOVE and it cannot be DISPLAYed. To manipulate an index the SET
statement must be used.
The major difference between a subscript and an index is that a subscript is a position in the table
(first element, 20th element, etc.). An index is a byte offset of an element relative to the
beginning of the table. Since the first element is 0 bytes away from the start of the table, it has an
index of 0. The 20th element (say each element is a PIC X(5)) starts 95 bytes from the start of the
table so its index is 95. When manipulating an index the programmer does not do so by this byte
offset. It is done by position in the table and the translation to byte offset is done internally by
COBOL.
See the algorithms page for sample code on loading and searching tables.
Also see OCCURS clause, Set.
Back to Table of Contents
Tables
Tables are the COBOL equivalent to arrays. It is a set of fields with the same name and the same
data type. To reference an individual element of the table a subscript or index must be used.
Tables are defined using the OCCURS clause.
See the algorithms page for sample code on loading and searching tables.
Back to Table of Contents
Truncation
Truncation is a phenomenon that occurs when the receiving field of a MOVE or a math operation
is not big enough to hold what it's getting. For alphanumeric fields truncation happens on the
right (move 'COBOL' to a PIC X(4) and you get 'COBO') and numeric it happens on the left
(move 1000005 to a PIC 9(06) and you get 5). No warnings, no messages. Just the loss of data.
Also see On Size Error.
Back to Table of Contents
77-level Fields
A working storage field can be declared with a level number of 77. The 77 must be in column 8,
the field cannot be a group-level field and the field cannot be part of a group-level field.
Back to Table of Contents
88-level Fields
A field declared with a level number of 88 is commonly known as a 'condition name'. This name
can be used anywhere a condition can be used and is generally more readable. Condition names
are declared immediately after the field they are associated with. They use no storage (they take
up no room).
For example your application contains a field named ACCT-TYPE which is PIC 999. One
particular section of code determines if the account is a checking account (account type 100, 110,
210 or 300), a savings account (type 150 or 175) or a CD/IRA (type 400). An IF statement could
look like:
IF WS-ACCT-TYPE = 100 OR 110 OR 210 OR 300
statement(s)
ELSE
IF WS-ACCT-TYPE = 150 OR 175
statement(s)
ELSE
IF WS-ACCT-TYPE = 400
statement(s)
END-IF
END-IF
END-IF
Logically accurate but not entirely clear what account types are what. Comments would help, but
condition names will help more. Define as:
01
WS-ACCT-TYPE
88 CHECKING-ACCT
88 SAVINGS-ACCT
88 CD-IRA-ACCT
PIC 999.
VALUE 100 110 210 300.
VALUE 150 175.
VALUE 400.
Now it's self-documenting. The added advantage is if another type of savings account is
developed it only needs added at the condition name. The IF statement doesn't change.
A specific value can appear in multiple condition names. Values associated with a condition
name can be specified with THRU (i.e. VALUES 90 THRU 99). When checking condition
names 'NOT' can be used. If a condition name only has one value a statement such as 'SET CDIRA-ACCT TO TRUE' is valid and is the equivalent to 'MOVE 400 TO WS-ACCT-TYPE'.
Also see Set.
Back to Table of Contents
Accept
The ACCEPT statement is used to get information from a source other than a data file (like the
keyboard or CPU clock).
The statement:
ACCEPT field.
will cause the program to wait until the enter key is pressed. Any data typed in before the enter
key is pressed will then be placed in field. See How do I ...? for issues with getting numeric data
in this manner. See the algorithms page for sample code on receiving and processing data
received interactively.
The ACCEPT statement can also be used to get information from the system clock such as the
current date and time:
ACCEPT
ACCEPT
ACCEPT
ACCEPT
field-1
field-2
field-3
field-4
FROM
FROM
FROM
FROM
DATE.
TIME.
DAY.
DAY-OF-WEEK.
Where:
field-2 is PIC 9(8). The time will be in hhmmsscc format where cc is hundredths of a
second. hh will be in military time (0-23)
field-3 is PIC 9(3). The value will represent the current Julian date, which is a number
from 1-366 representing the date as a number of days relative to the end of the previous
year (Jan 1st = 1, Feb 1st = 32, etc.).
which adds value (either a literal or a field) to field-1 and stores the result in field-1. A list of
fields can follow the TO which will add the value to each of them. A list of values can be before
the TO which would add all of them to field-1.
It is possible to add two values (either literals or fields) and store the result in a separate field
with the GIVING clause:
ADD value-1 TO value-2 GIVING field-1.
CALL 'PGM6F.OBJ'
USING WS-FLD-1 WS-FLD-2 WS-FLD-3
WS-FLD-4 WS-FLD-5
END-CALL.
See the algorithms page for sample code on calling another program.
Back to Table of Contents
Close
The CLOSE statement will close an open file. Attempting to close a closed file will produce a
run-time error.
One CLOSE statement can close multiple files.
CLOSE file-name-1
file-name-2.
Expression is any valid mathematical expression involving literals, fields and the following
symbols: + (add), - (subtract), * (multiply), / (divide), ** (exponentiation). To code 2 to the 3rd
power use '2 ** 3'.
The order of operations is as follows:
1. Exponentiation, from right to left
2. Multiplication and division, from left to right
3. Addition and subtraction, from left to right
Parenthesis can also be used to force the order in which the operations are carried out.
Expressions inside parenthesis are computed first, from the innermost parenthesis to the
outermost.
COMPUTE comes with a warning. Some compilers will round/truncate each intermediate result
as opposed to waiting until the end of all calculations. This can lead to erroneous results.
Also see Rounded, On Size Error, Truncation, Delimiters.
Back to Table of Contents
Copy
COPY will insert the contents of the specified file into the program containing the COPY when
the program is compiled. The file being copied is normally referred to as a copybook. COPYs
can appear in any of the divisions. A period must terminate the COPY.
Record layouts are commonly in copybooks. Every program that reads or writes the file can
contain a COPY instead of having the same record definition repeated in several programs. If the
record layout is changed the change needs to be in one place and the programs recompiled to
grab the more recent version.
FD
IN-CUSTOMER-MASTER
RECORD CONTAINS 1200 CHARACTERS.
COPY CUSTMAST.
A specific location for the copybook can be specified on the COPY by using either 'OF' or 'IN',
followed by the library name.
FD
IN-CUSTOMER-MASTER
RECORD CONTAINS 1200 CHARACTERS.
COPY CUSTMAST OF CPYBOOKS.
COPY supports a REPLACING clause, where text in the copybook is altered once it is inserted
in the program. The original copybook is unchanged. Literals and identifiers can be changed
simply by specifying them in the command. Text can also be replaced, but requires the source
and target text to be in between pairs of equal signs.
COPY CUSTMAST REPLACING CUST-NUMBER BY CUST-NBR.
COPY CUSTMAST REPLACING ==CUST-== BY ==CUSTOMER-==,
==9(5)== BY ==X(5)==.
The first will change the name of a field, assuming it exists in the copybook. The second will
change every occurrence of 'CUST-' to 'CUSTOMER-' and change all '9(5)' to 'X(5)'. Some
record layout copybooks will have a dummy prefix on each field name and each time it is
COPYed the prefix is changed by a REPLACING on the COPY. This allows for the copybook to
used for multiple files in the same program - each COPY REPLACEs the dummy prefix with a
different value avoiding having multiple fields with the same name.
Back to Table of Contents
Corresponding
MOVE CORRESPONDING (or just MOVE CORR) is used with group-level fields. Whenever
the source and target group-level fields have elementary fields of exactly the same name then that
field will be moved. Consider the following:
01
GROUP-1.
05 FIELD-A
05 FIELD-B.
10 FIELD-C
10 FIELD-D
05 FIELD-E
05 FIELD-F
PIC 999.
PIC
PIC
PIC
PIC
X(12).
XXX.
99.
X.
01
GROUP-2.
05 FIELD-E
05 FIELD-A
05 FIELD-BB.
10 FIELD-C
10 FIELD-D
05 FIELD-G
PIC 99.
PIC 9(4).
PIC XXX.
PIC X.
PIC X(10).
The statement 'MOVE CORRESPONDING GROUP-1 TO GROUP-2' will cause both FIELD-A
and FIELD-E to be moved. FIELD-C and FIELD-D have different group-level names so they
don't correspond.
This command is very useful when reformatting records. It can replace dozens, even hundreds,
of moves.
Also see Move.
Back to Table of Contents
Delete
DELETE will delete the current record in a non-sequential file OPENed as 'I-O'. There must be a
current record, so a successful READ or READ NEXT must precede the DELETE.
DELETE OT-FILE RECORD.
See the algorithms page for sample code on using non-sequential files.
Also see Invalid Key.
Back to Table of Contents
Display
The DISPLAY statement is used to show information on the terminal screen. Any combination of
literals and fields can be displayed. All of the following are valid:
DISPLAY field-name.
DISPLAY 'Now performing paragraph 2000-READ'.
DISPLAY 'Employee number = ' WS-EMPLOYEE-NBR.
Can use the clause 'WITH NO ADVANCING' after the value being displayed to prevent the
cursor from dropping down a line on the screen. This can be useful for prompts for an ACCEPT
statement:
DISPLAY 'Enter a number: ' WITH NO ADVANCING.
ACCEPT WS-NBR.
which divides value (either a literal or a field) into field-1 and stores the result in field-1.
It is possible to store the result in a separate field with the GIVING clause. When using GIVING
you can opt to divide BY instead of divide INTO. This changes the positions of the divisor and
dividend:
DIVIDE value-1 INTO value-2 GIVING field-1.
DIVIDE value-1 BY value-2 GIVING field-1.
You can also specify the remainder of the division to be stored in a separate field (only valid with
GIVING):
DIVIDE value-1 INTO value-2
GIVING field-1
REMAINDER field-2.
While it is legal in COBOL to have REMAINDER when not working with integers it makes
little sense to do so.
Also see Rounded, On Size Error, Truncation, Delimiters.
Back to Table of Contents
Evaluate
The EVALUATE statement can be used to replace a nested- IF construct. It is the equivalent of a
CASE or SWITCH statement of other languages.
EVALUATE WS-GRADE
WHEN 100
DISPLAY 'PERFECT'
WHEN 90 THRU 99
DISPLAY 'A'
WHEN 80 THRU 89
DISPLAY 'B'
WHEN 70 THRU 79
DISPLAY 'C'
WHEN OTHER
DISPLAY 'WOULD YOU LIKE FRIES WITH THAT?'
END-EVALUATE.
Each 'WHEN' can only have one statement, though it can be a PERFORM. If multiple WHENs
are true only the first one checked will execute. The 'WHEN OTHER' is like a 'none of the
above'.
If two WHENs are 'stacked' (no statement between them) they are treated like an 'OR'. For
example:
EVALUATE WS-AGE
WHEN 0 THRU 4
WHEN 70 THRU 99
DISPLAY 'TAKE A NAP'
END-EVALUATE.
Condition names cannot be used when EVALUATEing a field. Condition names can only be
used with 'EVALUATE TRUE' or 'EVALUATE FALSE'. When EVALUATEing a field the
WHENs contain values, not conditions.
Use EVALUATE ALSO to evaluate multiple fields/conditions at the same time.
EVALUATE WS-SEX ALSO WS-MARITAL-STATUS
WHEN 'F' ALSO 'S'
MOVE 'MISS' TO WS-TITLE
WHEN 'F' ALSO 'M'
MOVE 'MRS.' TO WS-TITLE
WHEN 'M' ALSO 'S'
MOVE 'MR.' TO WS-TITLE
WHEN 'M' ALSO 'M'
MOVE 'POOR MR.' TO WS-TITLE
WHEN OTHER
DISPLAY 'CALL SECURITY'
END-EVALUATE.
You can use EVALUTE TRUE and FALSE with ALSO. Each WHEN will then contain one
condition for each TRUE or FALSE.
Back to Table of Contents
Exit
EXIT is used as the only statement in a paragraph that isn't supposed to do anything. This
typically is used in conjunction with PERFORM THRUs. The paragraph being PERFORMed
THRU is the one containing the EXIT.
PERFORM 300-READ-FILE THRU 300-EXIT.
. . . . . .
300-READ-FILE.
READ IN-FILE
AT END MOVE 'Y' TO WS-EOF-SW
GO TO 300-EXIT
END-READ.
. . . . (MUCH LOGIC) . . . .
PERFORM 400-WRITE-RECORD THRU 400-EXIT.
300-EXIT.
EXIT.
Exit Program
EXIT PROGRAM is used in a called program instead of a STOP RUN. It will return execution
to the calling program where a STOP RUN will terminate all currently running programs.
Also see Goback.
Back to Table of Contents
Go To
GO TO is used to transfer control to another part of the program. The target of a GO TO is a
paragraph name.
Unlike a PERFORM a GO TO will not return when the paragraph finishes.
GO TO 300-EXIT.
The statement(s) are only executed if the condition is true. Each IF is allowed to have an ELSE.
The statement(s) in the ELSE are only executed if the condition is false:
IF condition
statement(s)
ELSE
statement(s)
END-IF.
There must be at least one statement in either portion of the IF. If you do not want any processing
done you can use the CONTINUE or NEXT SENTENCE statement:
IF condition
CONTINUE
ELSE
statement(s)
END-IF.
IFs can be nested (one IF inside another). COBOL will match an ELSE or an END-IF with the
nearest IF that does not yet already have an ELSE or END-IF paired with it.
IFs can also be used to check types. An field can be checked to see if it contains valid numerics
with:
IF field IS NUMERIC
IS NOT NUMERIC is also valid. In the same manner a numeric field can be checked to see if IS
POSITIVE, IS NEGATIVE or IS ZERO.
The END-IF delimiter is not required. A period will end all IFs.
Also see Evaluate.
Back to Table of Contents
Initialize
The INITIALIZE command is used to set all of the values for fields in the same group-level field
to either 0 or spaces, depending on the field's definition. The statement:
INITIALIZE WS-GROUP.
where:
01
WS-GROUP.
05 WS-FIELD-1
05 WS-FIELD-2
05 WS-FIELD-3
05 WS-FIELD-4
PIC
PIC
PIC
PIC
X(05).
999.
S9(04)V99.
X(100).
Where field-1 is an alphanumeric field and field-2 is a numeric field that will hold the count.
target has a few different possibilities. It can be the word CHARACTERS in which case field-2
holds the number of characters in the alphanumeric string. Or a specific character can
INSPECTed for using either ALL or LEADING followed by the character. Finally, any of these
forms can be ended with a BEFORE/AFTER INITIAL clause:
INSPECT
INSPECT
INSPECT
INSPECT
WS-A
WS-A
WS-A
WS-A
TALLYING
TALLYING
TALLYING
TALLYING
WS-N
WS-N
WS-N
WS-N
FOR
FOR
FOR
FOR
ALL '*'
LEADING SPACES
CHARACTERS AFTER INITIAL SPACE
',' BEFORE INITIAL '0'
The INVALID KEY clause is used with any type of non-sequential I-O statement. It specifies a
statement to be executed if the command fails. Any statement such as READ or WRITE with any
relative or indexed file should include this clause. For example:
MOVE WS-KEY TO FILE-KEY.
READ INDEX-FILE
INVALID KEY PERFORM 300-RECORD-NOT-FOUND
END-READ.
Upon an unsuccesful READ (for example, if no record in the file has that key) the specified
statement is executed instead of the program crashing. There is an optional NOT INVALID KEY
clause that can be included (must be after the INVALID KEY). It is best if only one statement is
used in either the INVALID KEY or NOT INVALID KEY clause.
See the algorithms page for sample code on using non-sequential files.
Back to Table of Contents
Merge
The merge is used to sort multiple files into one. Each of these files requires its own FD in the
FILE SECTION, as does the combined file. All of these files must obviously have the same
record format. The merge requires another entry in the FILE SECTION, an SD instead of an FD.
MERGE sd-file-name ON ASCENDING KEY sd-field-name
USING fd-input-file-name-1
fd-input-file-name-2
GIVING fd-output-file-name
To sort multiple fields list them in the desired order. DESCENDING KEYs can be mixed with
ASCENDING KEYs in the same MERGE (but only use 'ON' once). List the input files in the
desired order in the USING clause.
Like the SORT an OUTPUT procedure can be specified (requiring a RETURN) instead of the
GIVING, but the MERGE does not support the INPUT PROCEDURE option.
Back to Table of Contents
Move
The MOVE statement is used to place a value in a field. It is kind of like an assignment
statement in other languages though it does not allow for computations. Even though the
statement is a move, it is more like a copy. The data is still in its original place as well as the
receiving field. The standard form of statement is:
where value can be a literal or a field. A list of fields can follow the TO causing the value to be
MOVEd to each of the fields.
With a numeric move the source and destination are checked for the location of the decimal place
(if one is not explicitly defined it is assumed to be to the right of the rightmost digit) and the
move is done based on that. For example, MOVEing the value 80.375 to a PIC 9(06)V99 will
cause the receiving field to contain 80.37 and MOVEing the value 3.1415927 to a PIC 9(08) will
cause the receiving field to contain 3.
Alphanumeric and alphabetic moves first move the leftmost character of the sending field to the
leftmost character of the receiving field, then the next character, and so on. All group-level
MOVEs are considered alphanumeric.
If the receiving field is larger than the data being MOVEd then the field will be padded.
Alphanumeric fields are padded on the right with spaces, numerics are padded on the left with
zeroes. If a numeric has more decimal places than the data being MOVEd then zeroes will be
padded on the right in the decimal portion of the receiving field.
Also see Truncation, Corresponding.
Back to Table of Contents
Mulitply
The basic form of the multiply statement is:
MULTIPLY value BY field-1.
which multiplys value (either a literal or a field) by field-1 and stores the result in field-1.
It is possible to store the result in a separate field with the GIVING clause:
MULTIPLY value-1 BY value-2 GIVING field-1.
Occurs is used to define a table. It is followed by the number of elements in the table. COBOL
does not support dynamic tables - the size must be specified.
01
WS-TABLE.
05 WS-ELEMENT
PIC 9(5).
Defines a table with 100 elements. The allowable subscripts for this table are 1 through 100. To
access a specific element of the table you would use something like WS-ELEMENT (27). A
space is required before and after the parenthesis. The subscript can be a field but cannot be an
expression. The subscript can be a separate working-storage numeric field or COBOL can told to
create an index, like in the following:
01
WS-TABLE.
05 WS-ELEMENT
PIC 9(5).
WS-TABLE-AREA.
05 WS-TABLE
10 WS-KEY
10 WS-VALUE-1
10 WS-VALUE-2
FILLER
05 WS-DAYS-OF-WEEK
VALUE 'MONTUEWEDTHUFRISATSUN'.
OCCURS 7 TIMES.
Creates a table with 7 elements and also initializes them. This was not possible until a very
recent version of COBOL. A redfines had to be used.
See the algorithms page for sample code on loading and searching tables.
Back to Table of Contents
On Size Error
When used with one of the math verbs (ADD, SUBTRACT, MULTIPLY, DIVIDE, COMPUTE)
it allows COBOL to detect truncation and divide-by-zero situations and execute a specified
instruction instead of doing the calculation. The one statement can be a PERFORM. For
example:
file-name-1
file-name-2
OUTPUT file-name-3
file-name-4.
PERFORM paragraph-name.
PERFORM paragraph-name
WHILE condition.
PERFORM paragraph-name
UNTIL condition.
PERFORM paragraph-name
VARYING field-1
FROM value-1 BY value-2
UNTIL condition.
PERFORM paragraph-name value-1 TIMES.
When using the UNTIL option with a perform or in-line perform the 'UNTIL condition' clause
can be preceded by 'WITH TEST AFTER' to have COBOL check the condition after the loop
instead of before. This will cause the loop to always be executed at least once. This has the effect
of a REPEAT-UNTIL loop of other languages.
Also see Conditions Delimiters Sections.
Back to Table of Contents
Read
The read statement will read the next record from the specified file and place the data in the
record layout of that file's FD. The file must be already open as input. Reading an unopend file or
attempting to read beyond the end of a file will produce a run-time error. The AT END clause is
required.
READ file-name
AT END
statement
END-READ.
Optional clauses are NOT AT END and INTO. NOT AT END specifies a statement to be
executed if the read did not hit the end of the file. INTO specifies a working-storage field into
which the system will place the input record.
READ file-name
INTO
working-storage field
AT END
statement
NOT AT END
statement
END-READ.
Since this is still a "sequential" process the READ NEXT requires an AT END clause. The
optional NOT AT END clause is supported.
See the algortihms page for code examples.
Back to Table of Contents
Redefines
The REDEFINES clause allows you to have multiple field definitions for the same piece of
storage. The same data then can be referenced in multiple ways.
Take a simple example, useful for data validation:
01
01
WS-NUMBER-X
WS-NUMBER
PIC X(8).
REDEFINES WS-NUMBER-X
PIC 9(6)V99.
This portion of the data division only consumes 8 bytes of storage, not 16. Each of the two PIC
clauses is describing the same 8 bytes of data, just doing it differently.
Once data is in WS-NUMBER-X it can be checked to see if it is numeric (IF WS-NUMBER-X
IS NUMERIC). If so, WS-NUMBER can then be used as part of a calculation. If the data
happens to be non-numeric then this type of code will prevent the program from choking. We
access the data as alphanumeric (any data allowed) to see if it is safe to access it as numeric
before actually attempting to do so.
Note that once the data was moved to WS-NUMBER-X it was also moved to WS-NUMBER
because they both describe the same portion of storage.
There are a few rules with REDEFINES:
A redefinition must have the same level number as the field it is redefining
The redefinition must immediately follow the field it is redefining (i.e. if an 05-level field
is being redefined then the redefinition must be the next 05-level field)
The redefinition should be the same size as the field it is redefining though not all
compilers require this
It is possible to redefine at the group level though each group-level field does not have to
the same number of elementary fields
Not all compilers allow VALUE with REDEFINES. It's a bad idea in any case
Release
The RELEASE statment is required in an INPUT PROCEDURE of a SORT. It is used to specify
that a record is to be included in the sort.
RELEASE sd-record-name
RELEASE sd-record-name FROM working-storage-field
REWRITE will update the current record in a non-sequential file OPENed as 'I-O'. There must
be a current record, so a successful READ or READ NEXT must precede the REWRITE.
Following the READ/READ NEXT and before the REWRITE some information on the record
will presumably be changed.
REWRITE IN-FILE-REC.
The field is the field with the OCCURS clause. WHEN specifies the condition on which to end
the search (usually when some field equals a table entry) Only one statement can be specified in
the WHEN but it can be a PERFORM. The AT END clause is optional, specifying one statement
to be executed if the entire table is searched without satisfying the WHEN condition. It is
recommended, however.
For example:
* ALWAYS SET THE INDEX TO 1 BEFORE A SEARCH
SET WS-INDX TO 1.
SEARCH WS-TABLE
AT END
MOVE ZEROES TO SALES-TAX
WHEN IN-STATE = WS-TABLE-STATE (WS-INDX)
MOVE WS-TABLE-TAX TO SALES-TAX
END-SEARCH.
There can be multiple WHENs but the search stops once the condition of a WHEN is satisfied.
To allow for multiple search matches use a PERFORM VARYING, which can increment an
index.
If the table entries are sequenced by the field being searched then a binary search can be used
instead. Use SEARCH ALL instead of SEARCH. It is more efficient than a regular search,
especially with large tables. The SEARCH ALL has some limitations:
See the algorithms page for sample code on loading and searching tables.
Back to Table of Contents
Set
Set can be used to manipulate an index:
SET WS-INDX TO WS-NUMBER.
SET WS-INDX UP BY 1.
SET WS-INDX DOWN BY 3.
Note that while an index is actually a byte offset within a table COBOL does not expect you to
work on that level. Setting an index to 2 will cause it to point to the 2nd element in the table,
regardless of its offset. Likewise, seting an index up one will move it to the next element in the
table, regardless of the size of the element. COBOL will translate it to the proper offset for you.
Set can also be used with condition names as an alternative to a MOVE. Consider the following:
01
WS-END-OF-FILE-SW
88 END-OF-FILE
PIC X
VALUE 'N'.
VALUE 'Y'.
This is the equivalent to "MOVE 'Y' TO WS-END-OF-FILE-SW" but it is more readable. Most
compilers will not allow a condition name with multiple values to be used in a SET. It is not a
good idea in any case.
Back to Table of Contents
Sort
The sort statement is used to sort a file. It requires a work file area that is defined in the FILE
SECTION, just like any other file, except it is an SD instead of an FD. The basic sort statement
looks like:
SORT sd-file-name ON ASCENDING KEY sd-field-name
USING fd-input-file-name
GIVING fd-output-file-name
Multiple fields can be used in the sort, just list them in the desired order. DESCENDING KEY
can be specified instead of ASCENDING KEY. DESCENDING KEY and ASCENDING KEY
can be combined in the same statement.
The SORT statement will open and close both the input and output files automatically. The
field(s) to be sorted on must be defined in the SD of the sort file.
An INPUT PROCEDURE can be specified instead of an input file. This allows the flexibility of
selecting specific records to be sorted or to do other types of processing before the sort.
Likewise, an OUTPUT PROCEDURE can be used instead of an output file. An INPUT
PROCEDURE requires a RELEASE statement and an OUTPUT PROCEDURE requires a
RETURN statement. For example:
SORT sd-file-name ON ASCENDING KEY sd-field-name
INPUT PROCEDURE IS paragraph-1
OUTPUT PROCEDURE IS paragraph-2
This statement will execute paragraph-1, perform the sort and then execute paragraph-2. An
INPUT PROCEDURE can be used with GIVING and an OUTPUT PROCEDURE can be used
with USING. Each of these options allows the THRU option (i.e. paragraph-a THRU
paragraph-b).
The clause 'WITH DUPLICATES IN ORDER' can be included in the statement (after the last
ASCENDING/DESCENDING KEY). This will cause any records with the same value(s) for the
sort field(s) to be kept in their original order. Not specifying this will not necessarily change their
original order, but there is no guarantee.
See the algorithms page for sample code on using the SORT statement.
Back to Table of Contents
Start
The Start statement is used to establish an access path for an indexed file with alternate keys (see
the algortihms page for code examples). Note that keys in alternate indexes are not necessarily
unique and the START is used in conjunction with the READ NEXT statement to find and
retrieve and these records.
START indexed-file-name
KEY EQUALS alternate-key-field-in-FD
END-START
The stop run statement will cause a normal termination to your program.
STOP RUN.
01
WS-DATE-FIELDS.
05 WS-YEAR
05 WS-MONTH
05 WS-DAY
WS-DISPLAY-DATE
PIC
PIC
PIC
PIC
.....
STRING WS-MONTH DELIMITED
'/'
DELIMITED
WS-DAY
DELIMITED
'/'
DELIMITED
WS-YEAR DELIMITED
INTO WS-DISPLAY-DATE.
BY
BY
BY
BY
BY
SPACE
SIZE
SPACE
SIZE
SPACE
which subtracts value (either a literal or a field) from field-1 and stores the result in field-1. A list
of fields can follow the FROM which will subtract the value from each of them. A list of values
can be before the FROM which would subtract all of them from field-1.
It is possible to store the result in a separate field with the GIVING clause:
SUBTRACT value-1 FROM value-2 GIVING field-1.
01
WS-NAME-FIELDS.
05 WS-FIRST
05 WS-MIDDLE
05 WS-LAST
WS-WHOLE-NAME
PIC
PIC
PIC
PIC
X(10).
X.
X(14).
X(25) VALUE 'HOMER J SIMPSON'.
.....
UNSTRING WS-WHOLE-NAME DELIMITED BY SPACE
INTO WS-FIRST, WS-MIDDLE, WS-LAST.
The above statement will take the all of WHOLE-NAME, up to but not including the 1st space,
and place it into WS-FIRST. The the part that is between the 1st and 2nd spaces, not including
either one, is placed in WS-MIDDLE, and so on.
Also see String.
Back to Table of Contents
Usage
USAGE can be used in conjunction with the PIC clause to specify how numeric data is to be
stored. The most common options are DISPLAY (the default), COMP and COMP-3. COMP is
short for COMPUTATIONAL, which can also be used. The words 'USAGE IS' are optional.
USAGE is only valid with numeric fields. It can be specified as follows:
01
WS-FIELDS.
05 WS-DISPLAY-1
PIC 9(4).
05
05
05
WS-DISPLAY-2
WS-COMP-1
WS-COMP3-1
PIC 999
USAGE IS DISPLAY.
PIC S9999
USAGE IS COMPUTATIONAL.
PIC 9(5)V99 COMP-3.
CALL 'PGM2.OBJ'
USING WS-FIELD-1, WS-FIELD-2, WS-FIELD-3
END-CALL
(In called program)
PROCEDURE DIVISION USING LK-FIELD-A, LK-FIELD-B, LK-FIELD-C
See the algorithms page for sample code on calling one program from another.
Back to Table of Contents
Value
Value allows you to initialize a field at the same time it is defined. The VALUE clause follows
the PIC clause and must be the proper type of data. The value can be changed in code at any
time.
05
05
WS-NBR-LINES-PER-PAGE
FILLER
PIC 99
VALUE 60.
PIC X(6) VALUE 'PAGE: '.
Some compilers will require the VALUE data to be the proper size also, others will truncate to
fit. Most compilers will not allow VALUEs in input FDs - it is a bad idea in any case.
Also see Continuation Initialize.
Back to Table of Contents
Write
The write statement will write data to the specified file. The file must be opened for output.
Attempting to write to an unopened file or a file opened for input will produce a run-time error.
WRITE record-name.
Optional clauses are FROM, BEFORE and AFTER. FROM specifies a working-storage field
from which the system will select the data that is to be written. FROM can appear with either
BEFORE or AFTER.
BEFORE and AFTER specify actions to be taken by the printer along with writing a record of
data. You can either specify the number of lines that are to be advanced or you can specify
advancing to the top of the next page. BEFORE and AFTER cannot appear in the same write.
WRITE record-name
FROM working-storage field
END-WRITE.
WRITE record-name
AFTER ADVANCING value LINES
END-WRITE.
WRITE record-name
AFTER PAGE
END-WRITE.