COBOL Textbook

Free-format COBOL in GnuCOBOL: what changed from columns 8 and 12

The same COBOL program written twice, in fixed format and in free format, with the column rules that shaped it and where GnuCOBOL and IBM disagree.

Published
Updated
Dialect
GnuCOBOL 3.x, free format
Status
Compiled and run with GnuCOBOL 3.2
Length
2,691 words, 12 min

COBOL source used to be punched on cards, and the card decided what went where. Column 7 said whether the line was a comment. Columns 8 to 11 held the things that start a structure. Columns 12 to 72 held everything else. Modern GnuCOBOL will still compile source in that shape, and it will also compile source with no column rules at all. This lesson writes one payroll program twice, once in each format, so you can see exactly what the columns were doing and what you give up when you stop using them.

Both listings were desk-checked line by line against the GnuCOBOL Programmer's Guide, the GnuCOBOL Manual, and the IBM Enterprise COBOL 6.4 Language Reference, and on 29 October 2026 we compiled and ran both with GnuCOBOL 3.2: each printed the payroll shown further down, line for line. That matters more here than in most lessons, because column errors are precisely the kind of mistake a compiler catches and an eye slides over. So the Python companion, /code/cobol-free-format-columns-8-and-12.py, does the column checking itself: it walks the fixed-format listing and checks every line against the rules quoted below, then proves the two listings are the same program, then replays the payroll so that every number printed further down comes from something we actually ran.

The program, in free format

PAY-EDIT reads a file of timecards, pays anything over forty hours at one and a half times the hourly rate, and totals the run. Here it is with no column rules in force:

>>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. PAY-EDIT.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
    SELECT Time-Card-File
        ASSIGN TO "datasets/cobol-free-format-columns-8-and-12.dat"
        ORGANIZATION IS LINE SEQUENTIAL
        FILE STATUS IS WS-FS.
DATA DIVISION.
FILE SECTION.
FD  Time-Card-File.
    COPY "cobol-free-format-columns-8-and-12.cpy".
WORKING-STORAGE SECTION.
77  WS-FS                   PIC XX.
77  WS-Standard-Hours       PIC 9(3)V99 VALUE 40.00.
77  WS-Overtime-Factor      PIC 9V9     VALUE 1.5.
77  WS-Basic-Hours          PIC 9(3)V99 VALUE 0.
77  WS-Overtime-Hours       PIC 9(3)V99 VALUE 0.
77  WS-Basic-Pay            PIC 9(6)V99 VALUE 0.
77  WS-Overtime-Pay         PIC 9(6)V99 VALUE 0.
77  WS-Gross-Pay            PIC 9(6)V99 VALUE 0.
01  WS-Flags.
    05  WS-EOF-Flag         PIC X VALUE "N".
        88  End-Of-Cards          VALUE "Y".
PROCEDURE DIVISION.
Pay-One-Card.
    ADD 1 TO WS-Cards
    IF TC-Hours > WS-Standard-Hours
       MOVE WS-Standard-Hours TO WS-Basic-Hours
       SUBTRACT WS-Standard-Hours FROM TC-Hours
           GIVING WS-Overtime-Hours
       ADD 1 TO WS-With-Overtime
    ELSE
       MOVE TC-Hours TO WS-Basic-Hours
       MOVE 0 TO WS-Overtime-Hours
    END-IF
    COMPUTE WS-Basic-Pay ROUNDED =
        WS-Basic-Hours * TC-Rate
    COMPUTE WS-Overtime-Pay ROUNDED =
        WS-Overtime-Hours * TC-Rate * WS-Overtime-Factor
    ADD WS-Basic-Pay TO WS-Overtime-Pay GIVING WS-Gross-Pay.

That is an excerpt; the shipped file /code/cobol-free-format.cob has the counters and the report paragraphs too. The record layout comes in from a copybook, the arrangement described in the lesson on COPY and REPLACING.

The same program, on a card

The other listing, /code/cobol-free-format-fixed.cob, is the identical program under the old rules. The difference is visible before you read a word of it:

001300 IDENTIFICATION DIVISION.
001400 PROGRAM-ID. PAY-EDIT.
001500 ENVIRONMENT DIVISION.
001600 INPUT-OUTPUT SECTION.
001700 FILE-CONTROL.
001800     SELECT Time-Card-File
001900      ASSIGN TO "datasets/cobol-free-format-columns-8-and-12.dat"
002000         ORGANIZATION IS LINE SEQUENTIAL
002100         FILE STATUS IS WS-FS.
002200 DATA DIVISION.
002300 FILE SECTION.
002400 FD  Time-Card-File.
002500     COPY "cobol-free-format-columns-8-and-12.cpy".
002600 WORKING-STORAGE SECTION.
002700 77  WS-FS                   PIC XX.
Listing 4.2-1. Lines 13 to 27 of cobol-free-format-fixed.cob.

Those leading digits are not line numbers in any language sense. IBM's reference-format page defines the areas by column: "Sequence number area: Columns 1 through 6", "Indicator area: Column 7", "Area A: Columns 8 through 11", "Area B: Columns 12 through 72". Of the sequence number area IBM says only that it "can be used to label a source statement line. The content of this area can consist of any character in the character set of the computer." On a deck of cards, that label was what let you put the deck back together after you dropped it.

The GnuCOBOL Manual describes the same geometry for its -fformat=fixed setting: source is divided into "columns 1-6, the sequence number area; column 7, the indicator area; columns 8-72, the program-text area; and columns 72-80 as the reference area". Read that last clause twice. It gives column 72 to the program text and to the reference area at once, which cannot be right as stated, and the classic boundary is that the text stops at 72 and the rest of the card is ignored. We have not tested what the compiler does at that boundary, and the IBM pages we read define their four areas and then stop at column 72 without describing anything beyond it, so we are leaving the exact status of columns 73 to 80 as something the documents we could reach do not settle between them. Nothing in either listing reaches column 73, which sidesteps the question entirely.

What has to start in Area A

Area A is four columns wide, and it exists to mark the things that begin a structure. IBM lists what must start there: division headers, section headers, "paragraph headers or paragraph names", the "level indicators (FD and SD) or level-numbers (01 and 77)", DECLARATIVES and END DECLARATIVES, and the end program, class, and method markers. Everything else goes in Area B, and IBM notes that a level number that may begin in either area "is a one- or two-digit integer with a value of 02 through 49, 66, or 88".

That rule is why the fixed listing indents the way it does. IDENTIFICATION DIVISION., FILE-CONTROL., FD, the 77 items, the 01 group, and the paragraph names all begin at column 8. SELECT, COPY, the 05 and 88 entries, and every statement begin at column 12 or later. It is also why a COBOL programmer reading a listing can find the structure by running an eye down a single column, which is a genuine advantage of the format and the thing you lose first when you abandon it.

The indicator column is the other piece of machinery. IBM: "A comment line is any line with an asterisk (*) or slash (/) in the indicator area", where the slash additionally "causes the compiler to start a new page for the source listing", a hyphen marks continuation of a word or literal from the previous line, and "A debugging line is any line with a D (or d) in the indicator area of the line". The twelve header comments in the fixed listing are asterisk lines of exactly that kind.

Turning the columns off

The Programmer's Guide (2.1.16) says the compiler "can be instructed to operate in either mode in any of the following four ways": the -fixed and -free switches; the SOURCEFORMAT AS FIXED and SOURCEFORMAT AS FREE clauses of the >>SET directive; the FORMAT IS FIXED and FORMAT IS FREE clauses of >>DEFINE; and the >>SOURCE directive, written >>SOURCE FORMAT IS FREE or >>SOURCE FORMAT IS FIXED. In free format a line may be up to 255 characters, "with no specific requirements as to what should appear in which columns".

There is a small paradox in the directive, and it is worth understanding because it explains a habit you will see in a lot of GnuCOBOL source. The guide's rule is that when the compiler is currently in fixed format, "the >> must begin in column 8 or beyond, provided no part of the directive extends past column 72". The compiler starts in fixed format by default. So the line that announces free format has to obey the fixed-format rules, which is why most GnuCOBOL programs written for both worlds put the directive at column 8 — including every other listing on this site.

The listing here does not. It starts >>SOURCE FORMAT IS FREE in column 1, which leans on a change that arrived in GnuCOBOL 3.2. The project's NEWS file for the 3.x branch records that if a format is not specified, "the compiler tries to automatically recognize the format, using either fixed or free, depending on column 7 in the first non-space line", and that the detection "can be disabled by setting the format manually with -free, -fixed or -fformat".

Count seven characters into that first line and you land on the C of SOURCE. What the NEWS entry does not say is what the compiler concludes from a given character, and we have no compiler here to ask. Our expectation is that a column 7 holding something other than a blank or a comment indicator is taken as free format, which would make this file compile with no option at all, but that is an inference from a one-sentence release note rather than documented behaviour, and it is the one claim in this lesson we would not want you to take on trust. The certain route is to say which format you mean: -free on the command line, or the directive at column 8 where the fixed-format rule can accept it, which is what every other listing on this site does.

The formats 3.2 added

The Guide documents two modes. The Manual documents rather more, because GnuCOBOL 3.2 added a -fformat dialect option along with extended SOURCE FORMAT directives. From the Manual's own descriptions:

Table 4.2-1
Format What it is
fixed the default: sequence area 1-6, indicator 7, program text 8-72
free "The program-text area starts in column 1 and continues till the end of line (effectively 255 characters in GnuCOBOL)"
cobol85 "Fixed format with enforcements on the use of Area A"
variable Micro Focus variable format: fixed, but program text runs to column 250
xopen X/Open free form; text may start in column 1 unless an indicator is present, lines up to 80 characters
xcard ICOBOL xCard: variable format with the right margin at column 255
crt ICOBOL free form, lines up to 320 characters
terminal ACUCOBOL-GT terminal format, where the debugging indicator is \D rather than D
cobolx like crt, except the indicator area is always column 1

The NEWS entry adds something the option list does not: those formats "come with Area A enforcement (except for XOPEN), that checks whether division, section, and paragraph names start in Area A", and the enforcement "additionally enables detection of missing periods before level numbers that lie in Area A in the DATA DIVISION". Plain -fixed does not advertise that checking, which is the practical reason to compile old source with -fformat=cobol85 when you want the compiler to be strict about the thing the format exists for. There is also -ftext-column, documented as the "Right margin column number for fixed-form reference-format", accepting 72 to 255.

Where GnuCOBOL and IBM differ

Table 4.2-2
Question GnuCOBOL 3.2 IBM Enterprise COBOL for z/OS 6.4
Area columns sequence 1-6, indicator 7, program text 8-72 (Manual) sequence 1-6, indicator 7, Area A 8-11, Area B 12-72
Selecting free format -free, -fformat=free, or the >>SOURCE, >>SET SOURCEFORMAT, >>DEFINE FORMAT directives not documented for z/OS on the reference-format pages we read; see the limitations below
Where a compiler directive goes in fixed mode the >> must begin "in column 8 or beyond", which is Area A "Compiler directives must start in Area B"
If no format is given since 3.2, detected from column 7 of the first non-space line no such detection documented
Area A enforcement only with cobol85 and the other 3.2 formats, not with plain fixed the Area A rules are the documented requirement
Other reference formats eight, including Micro Focus and ACUCOBOL-GT shapes the one fixed reference format
Free-format line length 255 characters not applicable

The directive row is the one that will bite a program meant for both compilers. GnuCOBOL wants >> at column 8 or beyond when it is in fixed mode, and column 8 is the first column of Area A; IBM says compiler directives must start in Area B, which begins at column 12. A directive placed at column 12 satisfies both readings, since GnuCOBOL's rule is a minimum rather than an exact column.

What the companion checks

Running python code/cobol-free-format-columns-8-and-12.py does four things and prints its results.

It reads the copybook, derives the field offsets from the PIC clauses, and confirms the layout is the one both programs copy: five elementary fields, 36 bytes, employee id at 1-5, name at 6-23, department at 24-26, hours at 27-31 and rate at 32-36, the two numerics being PIC 9(3)V99 with an implied decimal point. It then writes the 14 timecards of /datasets/cobol-free-format-columns-8-and-12.dat with LF endings and no header.

It walks the fixed listing against the rules quoted above. The result: 98 lines, all 98 carrying a sequence number, 12 comment lines with an asterisk in column 7, 29 entries beginning in Area A, 57 in Area B, and a longest line of 71 columns. Anything in the sequence area that is not a digit, anything but a space or an asterisk in column 7, a statement starting in Area A, a division header or level number starting in Area B, or any line reaching column 73 is reported as a problem. Writing that check found three over-long comment lines in our own copybook and one ASSIGN TO clause that ran to column 74, all of which are fixed in the shipped files.

It then reduces both listings to a stream of tokens, discarding comments, the format directive, and in the fixed file the sequence and indicator areas, and compares them. Both come to 321 tokens and the streams are identical, which is the claim the lesson rests on: these are the same program in two reference formats, not two programs that resemble each other. The free listing is 99 lines to the fixed listing's 98, the extra line being the directive, and 42 of its lines begin in column 1.

Finally it replays the payroll:

ID    NAME               DPT  HOURS     GROSS
10014 ABBOTT RAY         MNT  42.50   1,373.75
10023 BLACKWOOD IMOGEN   ADM  40.00   1,150.00
10031 CHAUDHRY NADIA     MNT  37.25   1,121.23
10046 DELACROIX HUGO     SHP  48.00   1,380.60
10052 ESPOSITO MARCO     SHP  40.25   1,071.96
10068 FONSECA RITA       ADM  35.00   1,162.00
10074 GREENHALGH OWEN    MNT  44.75   1,479.73
10089 HIRANO YUKI        QLT  40.00   1,396.00
10095 IVERSEN BRITT      SHP  52.50   1,559.81
10103 JELLICOE MAREN     QLT  38.50   1,343.65
10117 KOVALENKO PAVLO    MNT  40.10   1,208.52
10124 LAMPEDUSA GINA     ADM   0.00       0.00
10138 MBEKI THANDIWE     QLT  45.00   1,657.75
10142 NORDSTROM ERIK     SHP  41.75   1,131.69
Timecards read          14
With overtime            8
Overtime pay          1,503.81
Total gross pay      17,036.69

Four rows are there deliberately. Card 10023 is at exactly 40.00 hours and gets no overtime, because the test is TC-Hours > WS-Standard-Hours and forty is not more than forty. Card 10117 is at 40.10 and does: six minutes of overtime, worth 4.52. Card 10124 worked no hours and is paid nothing rather than being skipped. And card 10031 is the rounding case: 37.25 hours at 30.10 gives 1,121.225 exactly, which ROUNDED takes to 1,121.23, following the rule described in the lesson on COMPUTE and ROUNDED.

Compile and run

python code/cobol-free-format-columns-8-and-12.py
cobc -x -free -I code -o pay-edit code/cobol-free-format.cob
cobc -x -fixed -I code -o pay-edit-fixed \
    code/cobol-free-format-fixed.cob
./pay-edit
./pay-edit-fixed

Run these from the folder holding code/ and datasets/, since the ASSIGN names a relative path. Both compiles name their format rather than relying on detection: add -free to the first command if your GnuCOBOL predates 3.2, or if you would rather not depend on the column 7 reading described above. Adding it is harmless either way.

The copybook, and a rule worth keeping

One copybook serves both listings. Its level 01 starts in column 8 and no line reaches column 73, so the text is legal under either format, and nothing in it depends on which format is in force where it is copied. That is a deliberate discipline rather than a language requirement, and it is the safe course: we could find no statement in the Programmer's Guide about whether a source-format directive in a program carries into a copybook that program copies.

It is a discipline this site has not always kept. Four earlier copybooks here begin in column 1 and are copied by free-format programs, which works only if GnuCOBOL applies the current free format to copied text. They should be reformatted to column 8, and they will be once there is a compiler to prove it either way.

Limitations

Both listings compile and run under GnuCOBOL 3.2, which we checked on 29 October 2026; we have not compiled them with any other compiler. The companion checks the columns, the structure, and the arithmetic, but it is not a COBOL compiler and cannot tell you that the program is valid COBOL; it can only tell you it is laid out correctly and that the two versions agree.

Two questions in the table above are open rather than answered. We could not find free-form source format documented for Enterprise COBOL for z/OS 6.4 on the reference-format pages we read, and the absence of a statement is not the same as a statement of absence, so the row says what we could not verify rather than asserting IBM has no such support. The status of columns 73 to 80 is similarly unsettled between the two vendors' documents as we read them today.

The Programmer's Guide describes itself as documenting a 3.1 build, so for the -fformat option, the extra reference formats, the Area A enforcement and the automatic detection we relied on the Manual and the 3.x NEWS file instead. All of those are 3.2 features, and none of this lesson's claims about them apply to 3.0 or 3.1. If you are reading old source with a modern compiler, -fformat=cobol85 is the setting that will hold you to the rules the source was written under.

Correction, 29 October 2026: the build commands shown before named the sources cobol-free-format-columns-8-and-12.cob and cobol-free-format-columns-8-and-12-fixed.cob, and GnuCOBOL 3.2's cobc refuses a source file whose base name is longer than 31 characters ("invalid file base name ... length exceeds maximum"), even with -o, so both failed as printed. The listings are now shipped as cobol-free-format.cob and cobol-free-format-fixed.cob, and the old download addresses redirect there. The same day we compiled and ran both with GnuCOBOL 3.2, and each printed the payroll shown here line for line, so the page now says that instead of calling the listings desk-checked only.

Index terms cobol, gnucobol, free format, reference format, area a