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