COBOL Textbook

GnuCOBOL -std=ibm and other dialects: what each one changes

What cobc -std=ibm actually switches in GnuCOBOL 3.2, read from its dialect files, and one program whose output changes when the dialect does.

Published
Dialect
GnuCOBOL 3.x, free format; meant to be compiled three ways:
Status
Desk-checked, not compiled
Length
2,466 words, 11 min

GnuCOBOL can compile the same source as if it were written for several other compilers, and -std is the switch that picks which one. Most people meet it as -std=ibm, because they have a program from a z/OS shop and want it to compile on a laptop. This lesson answers two questions about that switch: what does -std=ibm change, setting by setting, and does it change what a compiled program prints? It does. The program at the end of the lesson prints different numbers under the default dialect and under -std=ibm, from the same source and the same data.

What was run and what was not. cobc is not installed on the machine this lesson was prepared on, so the COBOL listing has not been compiled. Everything below was read from the GnuCOBOL 3.2 release, downloaded from the GNU project's server on October 28, 2026, where 3.2 is still the newest release listed: the dialect files in its config folder, the compiler and runtime source, and its test suite. The settings tables were printed by the Python companion, /code/gnucobol-std-dialects-ibm.py, which reads the dialect files the way the 3.2 compiler reads them; those are real runs. The program output further down is the expected output, worked out by the same companion from the 3.2 source; its rules pass 15 checks, six of which compare them with whole cases from GnuCOBOL's own test suite. It is not a captured run. If a compiled run ever disagrees with it, the compiler wins and this page is wrong.

What -std actually does

-std=NAME makes cobc load one file, NAME.conf, from its configuration folder. The 3.2 compiler builds the file name with nothing more than sprintf (ext, "%s.conf", cob_optarg) in cobc/cobc.c, then reads it. The Programmer's Guide (10.1.5) says the folder defaults to /usr/local/share/gnucobol/config on Unix-like systems unless COB_CONFIG_DIR says otherwise; cobc --info prints the folder your compiler uses.

The 3.2 help text (cobc/help.c) lists 19 names: default, cobol2014, cobol2002, cobol85, xopen, ibm-strict, ibm, mvs-strict, mvs, mf-strict, mf, bs2000-strict, bs2000, acu-strict, acu, rm-strict, rm, gcos-strict and gcos. The folder also holds realia-strict.conf and realia.conf, which the help text does not mention but the 3.2 test suite compiles with. The copy of the help text in the Programmer's Guide comes from an earlier build and stops at rm.

Each vendor comes in two flavours. The strict file describes the vendor's compiler as closely as GnuCOBOL can. The plain name is a lax variant, and ibm.conf is only three lines of substance:

include "ibm-strict.conf"
include:        "ibm.words"
include "lax.conf-inc"

The note at the top of lax.conf-inc says what the third line is for: it allows "features that the original compilers don't support (larger lengths, syntax variations,...)". So -std=ibm is IBM's behaviour with GnuCOBOL's tolerance, and -std=ibm-strict is IBM's behaviour with IBM's limits.

Three reading rules from cobc/config.c explain the rest. A later line overrides an earlier one, so whatever lax.conf-inc sets wins over ibm-strict.conf. A support value written with a plus sign, such as +obsolete, only relaxes: the reader applies it when the value already in force is stricter, and never over skip or ignore. And any -f option on the command line is applied after the file. cobc reads its options twice, loading -std and -conf files in the first pass and applying -f settings in the second, so -fbinary-truncate wins over the dialect file wherever it sits on the command line. The test suite checks exactly that, with the comment "configuration flag on command line must override all (no matter where it's used)".

The settings that differ

This is the companion's table for the settings that change how data is stored, how a running program behaves, or how strict the compiler is, in five dialects. It is a real run against the 3.2 config folder:

setting              default      ibm-strict   ibm          mvs          mf
binary-size          1-2-4-8      2-4-8        2-4-8        2-4-8        1--8
binary-truncate      yes          no           no           no           no
binary-byteorder     big-endian   big-endian   big-endian   big-endian   big-endian
pretty-display       yes          no           no           no           yes
move-ibm             no           yes          yes          yes          no
perform-osvs         no           yes          yes          yes          no
arithmetic-osvs      no           yes          yes          yes          no
sticky-linkage       no           yes          yes          yes          no
hostsign             no           yes          yes          yes          no
defaultbyte          init         0            0            0            " "
init-justify         no           yes          yes          yes          no
odoslide             no           yes          yes          yes          no
assign-clause        dynamic      external     external     external     dynamic
filename-mapping     yes          yes          yes          yes          yes
subscript-check      full         max          max          max          max
format               auto         cobol85      cobol85      cobol85      fixed
reserved-words       default      IBM          default      default      default
word-length          63           30           63           63           63
literal-length       8191         160          8192         8192         8192
pic-length           255          50           255          255          255
relax-syntax-checks  no           no           yes          yes          yes
complex-odo          no           yes          yes          yes          yes
indirect-redefines   no           yes          yes          yes          yes
larger-redefines     error        error        warning      warning      ok

The descriptions below are the compiler's own, from cobc/config.def in 3.2:

Table 4.5-1
Setting 3.2's description default ibm
binary-size "binary byte size - defines the allocated bytes according to PIC" 1-2-4-8 2-4-8
binary-truncate "numeric truncation according to ANSI" yes no
pretty-display "alternate formatting of numeric fields" yes no
move-ibm "MOVE operates as on IBM (left to right, byte by byte)" no yes
perform-osvs "exit point of any currently executing perform is recognized if reached" no yes
arithmetic-osvs "limit precision in intermediate results to precision of final result (less accurate)" no yes
sticky-linkage "LINKAGE SECTION items remain allocated between invocations" no yes
hostsign "allow hexadecimal value 'F' for NUMERIC test of signed PACKED DECIMAL field" no yes
defaultbyte "default initialization for fields without VALUE" init 0
init-justify "applies JUSTIFY with VALUE clause" no yes

Two rows deserve a second look before any program is moved. defaultbyte is init in the default dialect, which the same description defines as "initialize to PICTURE/USAGE", so a numeric item with no VALUE starts at zero. Under -std=ibm it is 0, which the description lists as a "decimal 0..255 representing a character": every byte of an item without VALUE starts as binary zero, and a PIC 9 field full of binary zeros is not a valid number. A program that adds to a counter it never initialised can work under the default dialect and fail under -std=ibm. The other is format: the default is auto, and the IBM files set cobol85, the fixed card layout with Area A checking, so a free-format source needs -free or a >>SOURCE FORMAT IS FREE line when it is compiled with -std=ibm. Our listing starts with that line.

The reserved words

The reserved-word list changes too, and here strict and lax really part. ibm-strict.conf says reserved-words: IBM, which makes the compiler use ibm.words as the complete list; the file's own header says that in this case "the default reserved word list will not be used". ibm.conf includes the same file instead, and lax.conf-inc then sets reserved-words: default, so the IBM entries are added to GnuCOBOL's full built-in list. The companion's --words option prints it:

-std=default     built-in default list
-std=ibm-strict  ibm.words only (462 entries)
-std=ibm         built-in default list + 462 entries from ibm.words

The test suite has the case that shows the difference. A copybook-style record using USAGE BINARY-LONG, a GnuCOBOL word IBM does not have, fails under the strict dialect and compiles under the lax one. The expected messages, from syn_misc.at:

Table 4.5-2
Command Result in the 3.2 test suite
cobc -fsyntax-only -std=ibm-strict prog.cob error: 'BINARY-LONG' is not defined, but is a reserved word in another dialect
cobc -fsyntax-only -std=ibm-strict -freserved=BINARY-LONG prog.cob compiles
cobc -fsyntax-only -std=ibm prog.cob compiles

To see the list your own compiler uses, the Programmer's Guide points to cobc --list-reserved (2.1.1, where it adds that the list is "subject to variation depending on usage of the --std line command"), and its Appendix C1 gives the per-dialect form, cobc -std=dialect --list-reserved.

One paragraph, every dialect

Dialects also decide how loudly the compiler complains about old syntax. The 3.2 test suite compiles a short program with an AUTHOR. paragraph in the IDENTIFICATION DIVISION under each -std. These are its expected results, copied from configuration.at:

Table 4.5-3
-std Result
default warning: AUTHOR is obsolete in GnuCOBOL
cobol85 warning: AUTHOR is obsolete in COBOL 85
cobol2002 error: AUTHOR does not conform to COBOL 2002
cobol2014 error: AUTHOR does not conform to COBOL 2014
bs2000-strict error: AUTHOR does not conform to BS2000 COBOL
ibm-strict warning: AUTHOR is obsolete in IBM COBOL
mvs-strict warning: AUTHOR is obsolete in IBM COBOL for MVS & VM
mf-strict warning: AUTHOR is obsolete in Micro Focus COBOL
acu-strict warning: AUTHOR is obsolete in ACUCOBOL-GT
rm-strict warning: AUTHOR is obsolete in RM-COBOL
gcos-strict warning: AUTHOR is obsolete in GCOS
xopen warning: AUTHOR used
realia-strict no message
ibm, mf, acu, rm, mvs, gcos, bs2000, realia no message

The lax dialects are silent because lax.conf-inc sets comment-paragraphs: ok.

A program that prints different numbers

The listing, /code/gnucobol-std-dialects-ibm.cob, declares four USAGE COMP items, which GnuCOBOL treats as USAGE BINARY:

01 WS-Tiny     PIC 9(2)  COMP VALUE 12.
01 WS-Count    PIC 9(4)  COMP VALUE 5000.
01 WS-Delta    PIC S9(4) COMP VALUE -12.
01 WS-Total    PIC 9(5)  COMP VALUE 12345.
Listing 4.5-1. Lines 23 to 26 of gnucobol-std-dialects-ibm.cob.

For each one it prints the size in bytes and the value as DISPLAY shows it. FUNCTION LENGTH of an item that is not national returns its size in bytes (cob_intr_length in libcob/intrinsic.c returns srcfield->size):

    MOVE FUNCTION LENGTH(WS-Tiny) TO WS-Bytes
    DISPLAY "WS-TINY   PIC 9(2)  COMP  BYTES " WS-Bytes
            "  SHOWS " WS-Tiny
Listing 4.5-2. Lines 33 to 35 of gnucobol-std-dialects-ibm.cob.

Then it adds 7000 to the 5000 in WS-Count. The answer, 12000, has five digits and the PICTURE allows four:

    ADD 7000 TO WS-Count
    DISPLAY "ADD 7000 TO WS-COUNT            SHOWS " WS-Count
Listing 4.5-3. Lines 48 to 49 of gnucobol-std-dialects-ibm.cob.

Compiled with plain cobc -x, the 3.2 source says it prints:

WS-TINY   PIC 9(2)  COMP  BYTES 01  SHOWS 12
WS-COUNT  PIC 9(4)  COMP  BYTES 02  SHOWS 5000
WS-DELTA  PIC S9(4) COMP  BYTES 02  SHOWS -0012
WS-TOTAL  PIC 9(5)  COMP  BYTES 04  SHOWS 12345
ADD 7000 TO WS-COUNT            SHOWS 2000
WS-COUNT IS 2000

Compiled with cobc -x -std=ibm, the same source should print:

WS-TINY   PIC 9(2)  COMP  BYTES 02  SHOWS 00012
WS-COUNT  PIC 9(4)  COMP  BYTES 02  SHOWS 05000
WS-DELTA  PIC S9(4) COMP  BYTES 02  SHOWS -00012
WS-TOTAL  PIC 9(5)  COMP  BYTES 04  SHOWS 0000012345
ADD 7000 TO WS-COUNT            SHOWS 12000
WS-COUNT IS 12000

Every line differs, and three settings from the table account for all of it.

binary-size decides the bytes. Under 1-2-4-8 a COMP item with one or two digits gets one byte, three or four digits get two, five to nine get four. Under 2-4-8 the smallest size is two bytes. That is the table in the comment of every dialect file, and it is what compute_binary_size in cobc/field.c does. Only WS-Tiny changes size here, from one byte to two, but a record layout with small COMP fields changes length when the dialect changes, and every field after them moves.

pretty-display decides how DISPLAY prints a binary item. With it on, libcob/termio.c edits the value into a picture of the item's own digits, with a leading sign if the item is signed: four digits for PIC 9(4), so 5000 prints as 5000 and -12 as -0012. With it off, the runtime prints the value with as many digits as the item's bytes can hold. The widths come from a table in termio.c, bin_digits[] = { 1, 3, 5, 8, 10, 13, 15, 17, 20 }, indexed by the size in bytes: five digits for two bytes, ten for four. A signed item always gets a sign, plus or minus, because the format is %+*.*lld (%+*.*I64d in Windows builds). That is where 05000, -00012 and 0000012345 come from. The test suite's "BINARY: full-print" case, which turns pretty-display off, expects 001 for a one-digit item in one byte and -001 for its signed twin, the same rule at a smaller size.

binary-truncate decides what the ADD keeps. With truncation on and no ON SIZE ERROR phrase, cobc/typeck.c compiles the ADD with the option it labels "Truncate binary field to digits in picture", and the runtime keeps the remainder after dividing by 10 to the power of the digit count (mpz_tdiv_r in cob_decimal_get_binary): 12000 leaves 2000. With truncation off, the only limit is the two bytes, which hold up to 65535 unsigned, so 12000 is stored whole. The EVALUATE after the ADD shows that this is the stored value and not a display effect. The test suite's own case, "Numeric MOVE with/without -fbinary-truncate", moves, computes and adds 30000 into a PIC 9(4) COMP item and expects "x IS ZERO" three times by default and "x IS 30000" three times with -fno-binary-truncate.

A program that relies on truncation, such as a counter that is meant to wrap at 9999, or one that relies on its absence, such as a binary field that routinely holds more digits than its PICTURE declares, gives different answers under the two dialects with no message at compile time. The ON SIZE ERROR lesson shows the portable way out: test for the overflow instead of relying on what the store does with it.

Overriding one setting

The command-line rule above means a dialect can be adjusted one setting at a time. cobc -x -std=ibm -fbinary-truncate keeps IBM's sizes and display and puts truncation back:

WS-TINY   PIC 9(2)  COMP  BYTES 02  SHOWS 00012
WS-COUNT  PIC 9(4)  COMP  BYTES 02  SHOWS 05000
WS-DELTA  PIC S9(4) COMP  BYTES 02  SHOWS -00012
WS-TOTAL  PIC 9(5)  COMP  BYTES 04  SHOWS 0000012345
ADD 7000 TO WS-COUNT            SHOWS 02000
WS-COUNT IS 2000

When a project needs several changes, a dialect file of its own is tidier than a long command line. The test suite's own example of -conf is a file that includes default.conf, sets a name, and changes one setting; the same shape built on the IBM dialect would be:

include "ibm.conf"
name: "IBM rules with truncation"
binary-truncate: yes

Saved as shop.conf and used with cobc -x -conf=shop.conf, it should give the output above. The two options look for files differently (cb_load_conf and cb_load_conf_file in config.c): -std always reads from the configuration folder, while -conf takes the name as a path, and an include of a bare file name is looked for in the working folder first, then in the folder of the file that includes it, then in the configuration folder. Use -conf instead of -std, not together with it: loading a second file discards the first, and the test suite expects the warning "The previous loaded configuration 'GnuCOBOL' will be discarded." when both are given.

The dialect a program is meant for is worth writing down where the program lives. Every listing on this site carries a Dialect: line in its header for that reason, and this one names the three compile commands it was written for.

Compile and run

From the site folder, with GnuCOBOL 3.x installed:

cobc -x code/gnucobol-std-dialects-ibm.cob
./gnucobol-std-dialects-ibm
cobc -x -std=ibm code/gnucobol-std-dialects-ibm.cob
./gnucobol-std-dialects-ibm
python code/gnucobol-std-dialects-ibm.py --config /usr/local/share/gnucobol/config
python code/gnucobol-std-dialects-ibm.py --config /usr/local/share/gnucobol/config --expect ibm
python code/gnucobol-std-dialects-ibm.py --selftest

The second and fourth commands should print the two listings above. The companion needs the configuration folder of a GnuCOBOL installation; cobc --info names it, and a 3.2 source tree has the same files in config. With --config alone it prints the settings table, --expect prints the probe's expected output for a dialect (add -f options after it, as you would to cobc), --words prints the reserved-word summary, and --selftest runs its nine built-in checks. Given --testsuite gnucobol-3.2/tests/testsuite.src, the self-test also compares its storage, display and truncation rules with six cases from GnuCOBOL's test suite, 15 checks in all.

Limitations

  • Not compiled here. The COBOL listing was checked against the 3.2 source and test suite, not by a compiler, and its expected output was worked out by the companion. We do not know which warnings, if any, cobc 3.2 prints for it.
  • GnuCOBOL's idea of IBM, not IBM's. Every IBM column on this page is what GnuCOBOL's IBM files say. We did not compare them with an IBM compiler or with IBM's documentation for this lesson, and an IBM shop's own compile options can differ from what the files assume.
  • Micro Focus is in the table only. The probe's output under -std=mf is not traced here. One reason: in the Micro Focus dialect, 3.2 reads >>SOURCE FORMAT IS FREE as X/Open free-form source rather than GnuCOBOL's own free format (cobc/pplex.l), and we did not follow that through for this listing.
  • Behaviour settings, not every setting. The table shows 24 of the 127 settings the dialect files define. The rest are mostly support levels for single clauses and statements, which are easiest to read in the files themselves.
  • Big-endian only. All the dialects in the table store binary items big-endian. A binary-byteorder: native setting on a little-endian machine changes the bytes on disk, though not the values the program prints.

The useful habit is the one the probe makes visible: when a program moves between dialects, the PICTURE clauses stay the same and the storage under them does not. A layout with COMP fields, a counter that overflows, and a field that starts without a VALUE are the three places to look first.

Index terms cobol, gnucobol, cobc, dialects, std=ibm