GCOBOL(1)

๐Ÿ“ฆ version 15.3.0, in ubuntu questing, ubuntu resolute, ubuntu stonking

๐ŸŒˆ GCOBOL(1) โ€” the GCC COBOL Compiler ๐ŸŒˆ

okay so this is the manual page for gcobol, the GCC COBOL compiler, and bestie it is so serious ๐Ÿ’…โœจ

โœจ NAME โœจ

the name bit is short and sweet ๐Ÿ™ˆ gcobol is the GCC COBOL Front-end ๐ŸŒธ

โœจ SYNOPSIS โœจ

here's the full lineup of ways you can call it, and yes there are a lot of flags ๐Ÿ˜ญ๐Ÿซถ

gcobol [-Dname[=value]] [-E] [-fdefaultbyte=value] [-fsyntax-only]
       [-Icopybook-path] [-fmax-errors=nerror] [-nomain | -main filename
       | -main=filename -main=filename:program-id]
       [-fcobol-exceptions exception[,exception...]] [-copyext ext]
       [-ffixed-form | -ffree-form] [-findicator-column]
       [-finternal-ebcdic] [-dialect dialect-name] [-include filename]
       [-preprocess preprocess-filter] [-fflex-debug] [-fyacc-debug]
       filename [...]

โœจ DESCRIPTION โœจ

okay bestie, so gcobol takes your COBOL source code and compiles it into object code ๐Ÿ’ป, and if you want, it'll even make an executable binary or a shared object for you ๐Ÿฆ‹. As a GCC component it accepts all the options that affect code-generation and linking (so many, literally), and the COBOL-specific ones are listed below ๐Ÿ’…

๐ŸŽ€ Entry points: -main and -nomain

  • -main filename โ€” gcobol makes a main() function as the entry point, and it calls the first PROGRAM-ID in filename ๐Ÿ‘‘
    • -main is the default. If none of -nomain, -c, or -shared shows up in the command line, an implicit -main gets slipped in ahead of the first source file name ๐Ÿ™ˆ
  • -main=filename โ€” the .o object module for filename will include a main() entry point that calls the first PROGRAM-ID in filename โœจ
  • -main=filename:program-id โ€” the .o object module for filename will include a main() entry point that calls the program-id entry point ๐Ÿงš
  • -nomain โ€” no main() entry point gets generated by this compilation ๐Ÿฅฒ
    • -nomain is incompatible with -main, and it's implied by -shared. It's also implied by -c when there's no -main present ๐Ÿซถ
    • Check out the examples further down to see -main and -nomain in action ๐Ÿ‘€

๐ŸŒธ Defines and listings

  • -D name[=expr] โ€” defines a CDF name (for use with >>IF) so it has the value of expr ๐Ÿ“
  • -E โ€” writes the CDF-processed COBOL input to standard output in free-form reference format ๐Ÿ“„. Some non-COBOL markers show up to point out where copybook files got included, and blank lines are kept so the line numbers still match the input ๐Ÿฆ‹
    • Unlike the C compiler, this option does not stop compilation. If you want compilation stopped, add -fsyntax-only too ๐Ÿšซ

๐Ÿง Data and defaults

  • -fdefaultbyte=value โ€” value is a number from 0 to 255 that becomes the default for all WORKING-STORAGE data items with no VALUE clause ๐Ÿงธ. By default, alphanumeric items get blanks and numeric items get zero, but this option overrides that with value ๐Ÿ’œ

๐Ÿซง Syntax, copybooks and format

  • -fsyntax-only โ€” only the parser runs โœ…. It checks the code for syntax errors but doesn't do anything beyond that ๐Ÿ™ƒ
  • -copyext ext โ€” for the CDF directive COPY name, when name is unquoted, several varieties of name get tried, as described below under Copybooks ๐Ÿ“š. This option extends the names searched to include ext. If ext is all uppercase or all lowercase, both forms get tried, with preference given to the one you supplied. If ext is mixed-case, only that version gets tried ๐Ÿง
    • For example, with -copyext .abc given the CDF directive COPY name, gcobol adds โ€˜name.abcโ€™ and โ€˜name.ABCโ€™ to the possible names searched, in that order ๐Ÿ’–
  • -ffixed-form โ€” strict fixed-form reference format ๐Ÿ“: 72-character lines, a 6-character sequence area, and an indicator column. Data past column 72 gets ignored ๐Ÿ™ˆ
  • -ffree-form โ€” forces the COBOL input to be read as free-form reference format ๐ŸŒˆ. Line breaks don't matter, except that a * at the start of a line acts as a comment marker ๐Ÿ’ฌ. This is equivalent to -indicator-column 0 ๐Ÿงš
  • -findicator-column โ€” describes where the Indicator Area lives in a COBOL file in Reference Format ๐Ÿ“. The first 6 columns (the โ€œSequence Number Areaโ€) get ignored, and the 7th column (the Indicator Area) may hold a character of significance to the compiler ๐Ÿ‘€
    • Strictly speaking, reference format ignores data after column 72, but with this option gcobol accepts long COBOL lines, sometimes called extended source format ๐Ÿฆ–. Text past column 72 is treated as ordinary COBOL text. Line continuation stays in effect, as long as no text appears past column 72 โœจ
    • There's no maximum line length ๐Ÿคฏ. Regardless of source code format, the entire program could appear on one line
    • By default, gcobol auto-detects the source code format by examining the line that contains the text "program-id" ๐Ÿ”. When there are characters past column 72 on that line, the file is assumed to be extended source format, with the indicator area in column 7. Otherwise, columns 1-6 get examined. If those characters are all digits or blanks, the file is assumed to be fixed-form reference format, also with the indicator in column 7. If it isn't auto-detected as fixed-form reference format or extended source format, the file is assumed to be free-form reference format ๐Ÿ’…

๐Ÿ”ฅ Exceptions

  • -fcobol-exceptions exception [,exception...] โ€” by default, no exception condition is enabled (fatal ones included), and ISO standard exception conditions only turn on through the CDF TURN directive ๐Ÿ˜ค. This option enables one or more exception conditions by default, as though TURN had appeared at the top of the first source code file ๐Ÿ‘‘. It may appear more than once on the command line ๐Ÿ”
    • The value of exception is a Level 1, 2, or 3 exception condition name, as described by ISO/IEC 1989:2023. EC-ALL means enable all exceptions ๐Ÿ”ฅ
    • The -fno-cobol-exceptions form turns off exception, just as though >>TURN exception CHECKING OFF had appeared ๐Ÿซถ
    • > Not all exception conditions are implemented. Any that aren't will produce a warning message โš ๏ธ

๐Ÿ›‘ Error limits

  • -fmax-errors=nerror โ€” nerror is the number of error messages produced ๐Ÿงฎ. Without this option, gcobol tries to recover from a syntax error by resuming at the next statement, continuing until end-of-file ๐Ÿƒ. With it, gcobol counts the messages as they're produced and stops once nerror is reached โœ‹

๐Ÿ“ž CALL linking

  • -fstatic-call, -fno-static-call โ€” with -fno-static-call, gcobol never uses static linking for CALL program ๐Ÿ™…
    • By default, or with -fstatic-call, if program is an alphanumeric literal, gcobol uses static linkage. That means the compiler produces an external symbol program for the linker to resolve ๐Ÿ”—. (In the future, that will work with CONSTANT data items, too ๐Ÿ”ฎ)
    • With static linkage, if program isn't supplied by the source code module, another object file, or a library at build time, the linker will produce an โ€œunresolved symbolโ€ error ๐Ÿ˜ฌ
    • With -fno-static-call, gcobol always uses dynamic linking ๐Ÿฆ‹
    • This option affects the CALL statement for literals only. If program is a non-constant data item, it's always resolved using dynamic linking, with dlsym(3), because its value is determined at run time โฑ๏ธ

๐Ÿ—ฃ๏ธ Dialects

  • -dialect dialect-name โ€” by default, gcobol accepts COBOL syntax as defined by ISO/IEC 1989:2023, with some extensions for backward compatibility with COBOL-85 ๐Ÿ“–. To make the compiler more generally useful, this option supports some additional syntax ๐ŸŒ
    • The value of dialect-name may be:
      • ibm โ€” to indicate IBM COBOL 6.3 syntax, specifically STOP <number>
      • gnu โ€” to indicate GnuCOBOL syntax
      • mf โ€” to indicate MicroFocus syntax, specifically LEVEL 78 constants
    • Only a few of these non-standard constructs are accepted, and gcobol makes no claim to emulate other compilers ๐Ÿ™Š. But to the extent that a feature is popular but nonstandard, this option gives a way to support it, or add it ๐Ÿ’…

๐Ÿ“‚ Includes and filters

  • -include filename โ€” processes filename as if COPY โ€œfilenameโ€ appeared as the first line of the primary source file ๐Ÿ“Ž. If filename isn't an absolute path, the directory searched is the current working directory, not the directory containing the main source file ๐Ÿ“. The name is used verbatim. No permutations are applied, and no directories are searched ๐Ÿšซ
    • If multiple -include options are given, the files are included in the order they appear on the command line ๐Ÿ”ข
  • -preprocess preprocess-filter โ€” after all CDF text manipulation has been applied, and before the prepared COBOL is sent to the cobol1 compiler, the input may be further altered by one or more filters ๐Ÿงผ. Like sed(1), each preprocess-filter reads from standard input and writes to standard output ๐Ÿช„
    • To supply options to preprocess-filter, use a comma-separated string, similar to how linker options are supplied to -Wl. Do not put any spaces after the commas, because the shell will treat it as an option separator ๐Ÿ™…. gcobol replaces each comma with a space when preprocess-filter is invoked. For example, -preprocess tee,output.cbl invokes tee(1) with the output filename argument output.cbl, causing a copy of the input to be written to the file ๐Ÿ“
    • gcobol searches the current working directory and the PATH environment variable directories for an executable file whose name matches preprocess-filter. The first one found is used. If none is found, an error is reported and the compiler is not invoked ๐Ÿ’€
    • The -preprocess option may appear more than once on the command line. Each preprocess-filter is applied in turn, in order of appearance ๐Ÿ”
    • The preprocess-filter should return a zero exit status, indicating success. If it returns a nonzero exit status, an error is reported and the compiler is not invoked ๐Ÿฅฒ

๐Ÿ› ๏ธ Compiler debugging

  • -fflex-debug, -fyacc-debug โ€” produce messages useful for compiler development ๐Ÿง . The -fflex-debug option prints the tokenized input stream, and the -fyacc-debug option shows the shift and reduce actions taken by the parser ๐Ÿค“

โœจ COMPILATION SCENARIOS โœจ

okay so let's talk about actually building stuff ๐Ÿ› ๏ธ๐Ÿ’– these first three are all the same vibe:

gcobol xyz.cob
gcobol -main xyz.cob
gcobol -main=xyz.cob xyz.cob

They're equivalent ๐Ÿ’… xyz.cob gets compiled and gcobol slides in a main() function that calls the first PROGRAM-ID in the xyz.cob source file. main character energy ๐Ÿ‘‘

gcobol -nomain xyz.cob elsewhere.o

-nomain is the "nah, I've got my own main" flag ๐Ÿ™…โ€โ™€๏ธ It stops gcobol from generating a main(). That means elsewhere.o has to already have a main() entry point, or the linker will throw a โ€œmissing mainโ€ error ๐Ÿ’€

gcobol aaa.cob bbb.cob ccc.cob
gcobol -main aaa.cob bbb.cob ccc.cob

These two are equivalent ๐Ÿซถ All three source modules get compiled and linked together, plus a generated main() that calls the first PROGRAM-ID in aaa.cob.

gcobol aaa.cob bbb.cob -main ccc.cob
gcobol -main=ccc.cob aaa.cob bbb.cob ccc.cob

Same result here ๐Ÿฆ‹ You end up with an a.out executable that starts running at the first PROGRAM-ID in ccc.cob.

gcobol -main=bbb.cob:b-entry aaa.cob bbb.cob ccc.cob

This one's so specific it's giving sniper ๐ŸŽฏ You get an a.out that starts at the PROGRAM-ID b-entry.

gcobol -c aaa.cob
gcobol -c -main bbb.cob
gcobol -c ccc.cob
gcobol aaa.o bbb.o ccc.o

The first three each make a .o file ๐Ÿงš The bbb.o file is the special one because it'll contain a main() entry point that calls the first PROGRAM-ID in bbb. The last line links all three .o files into an a.out ๐ŸŒˆ


๐Ÿ“ EBCDIC ๐Ÿ“

the -finternal-ebcdic option is โœจ for mainframe COBOL programs that are meant for EBCDIC-encoded files โœจ Here's the tea: the COBOL text itself stays in ASCII, but character literals and field initial values turn into EBCDIC strings in the compiled binary. Any character data read from a file gets interpreted as EBCDIC too ๐Ÿ™ˆ The file data itself is not converted. The file is just assumed to be EBCDIC. String literals in the COBOL text do get converted, so you can actually compare them meaningfully with what's in the file ๐Ÿ’œ

Only file data and character literals are affected ๐ŸŽ€ Data read from and written to the environment, or taken from the command line, gets interpreted according to the locale(7) in force during execution. Same deal for ACCEPT and DISPLAY. Names the operating system already knows about, like file names and environment variable names, are processed verbatim ๐Ÿซถ

At the present time this is an all-or-nothing setting. Support for USAGE and CODESET, which would allow conversion between encodings, is a future goal, not something that exists yet ๐Ÿ˜ญ

See also โ€œFeature-set Variablesโ€, below ๐Ÿฆ‹


๐Ÿฆ‹ REDEFINES ... USAGE POINTER ๐Ÿฆ‹

okay so per ISO, an item that REDEFINES another can't be bigger than the item it redefines, unless that item is LEVEL 01 and not EXTERNAL ๐Ÿ“ gcobol has a little exception for this when you use -dialect ibm ๐ŸŒธ It relaxes the rule for REDEFINES with USAGE POINTER when the redefined member is a 4-byte USAGE COMP-5 (usually PIC S9(8)), or the other way around ๐Ÿ”ฅ In that case, the redefined member gets resized to 8 bytes so the pointer fits. This is what lets you do pointer arithmetic on a 64-bit system with source code that was written for a 32-bit system ๐Ÿ’…

See also โ€œFeature-set Variablesโ€, below โœจ


โœจ IMPLEMENTATION NOTES โœจ

gcobol is a gcc compiler, so it follows gcc conventions wherever that makes sense ๐Ÿงš Sometimes those conventions (and what users expect) clash with common mainframe practice. Unless the ISO spec requires otherwise, any clash gets resolved in favor of gcc ๐Ÿ‘‘

๐Ÿ”— Linking

Unlike C, the COBOL CALL statement implies dynamic linking, because for

CALL program

the program can be a variable whose value isn't determined until runtime ๐ŸŒ€ It can also be a compile-time constant, either an alphanumeric literal or a CONSTANT data item.

gcobol supports static linking where it can, unless you turn it off with -fno-static-call ๐Ÿ’– If the parameter's value is known at compile time, the compiler makes an external reference for the linker to resolve. That referenced program is normally supplied through an object module, a static library, or a shared object. If it's missing, the linker will report an โ€œunresolved symbolโ€ error, either at build time or, if you're using a shared object, when the program runs. This is intentional: it tells you about the error at the earliest possible moment ๐Ÿ™Œ

Programs that are expected to run fine even with an unresolved symbol (maybe because the program logic never hits that particular CALL) can use the -no-static-call option ๐Ÿฆ‹ That forces every CALL statement to be resolved dynamically, at runtime.

๐Ÿ’€ Implemented Exception Conditions

By default, per ISO, no EC is enabled ๐Ÿ™…โ€โ™€๏ธ Implemented ECs can be enabled on the command line or with the TURN directive. Trying to enable an EC that isn't implemented is treated as an error ๐Ÿšซ

An enabled EC that isn't handled by a DECLARATIVE gets written to the system log and to standard error. (The authors intend to make that an option ๐Ÿ‘€) A fatal EC that isn't handled with RESUME ends with a call to abort(3) and process termination ๐Ÿ’€

Not every Exception Condition is implemented ๐Ÿ˜ญ Trying to enable an EC that isn't implemented produces a warning message. These are the ones that are implemented:

  • EC-FUNCTION-ARGUMENT โ€” for these functions:
    • ACOS
    • ANNUITY
    • ASIN
    • LOG
    • LOG10
    • PRESENT-VALUE
    • SQRT
  • EC-SORT-MERGE-FILE-OPEN
  • EC-BOUND-SUBSCRIPT โ€” the subscript is not an integer, is less than 1, or is greater than occurs
  • EC-BOUND-REF-MOD โ€” the refmod start is not an integer, is less than 1, or is greater than the variable size. The length is not an integer, is less than 1, or start+length exceeds the variable size
  • EC-BOUND-ODO โ€” DEPENDING is not an integer, is greater than the occurs upper limit, or is less than the occurs lower limit. Also, the subscript is greater than DEPENDING for the sending item
  • EC-SIZE-ZERO-DIVIDE โ€” for both fixed-point and floating-point division โž—
  • EC-SIZE-TRUNCATION
  • EC-SIZE-EXPONENTIATION

As of this writing, no COBOL compiler documents a complete implementation of ISO/IEC 1989:2023 Exception Conditions ๐Ÿคฏ gcobol will prioritize the ECs that the user community deems most valuable ๐Ÿ’œ


๐ŸŒˆ EXTENSIONS TO ISO COBOL ๐ŸŒˆ

Standard COBOL has no provision for environment variables (the Unix and Windows kind) or command-line arguments ๐Ÿ˜ค So gcobol adds support for them, using syntax similar to GnuCOBOL ๐Ÿซถ ISO and IBM also define incompatible ways to return the program's exit status to the operating system. gcobol goes with IBM syntax ๐ŸŽ€

๐ŸŒฟ Environment Variables

To read an environment variable:

ACCEPT target FROM ENVIRONMENT envar

target is a data item defined in the DATA DIVISION, and envar names an environment variable. envar can be a string literal or an alphanumeric data item whose value is the name of an environment variable. The value of the named environment variable gets moved to target, and the rules are the same as for MOVE ๐Ÿ’…

To write an environment variable:

SET ENVIRONMENT envar TO source

source is a data item defined in the DATA DIVISION, and envar names an environment variable. Again, envar can be a string literal or an alphanumeric data item holding the name of an environment variable. The named environment variable gets set to the value of source โœจ

๐ŸŽ€ Command-line Arguments

To read command-line arguments, use the registers COMMAND-LINE and COMMAND-LINE-COUNT in an ACCEPT statement (only) ๐Ÿ“ Used without a subscript, COMMAND-LINE returns the whole command line as one single string. With a subscript, COMMAND-LINE is a table of command-line arguments ๐Ÿงš For example, if the program gets invoked like this:

./program -i input output

then this:

ACCEPT target FROM COMMAND-LINE(3)

moves input into target ๐Ÿฆ‹ The program name is the first thing in the whole command line, so it lives in COMMAND-LINE(1) of the COMMAND-LINE table.

To find out how many arguments were provided, use:

ACCEPT target FROM COMMAND-LINE-COUNT
If ACCEPT refers to a nonexistent environment variable or command-line argument, the target gets set to LOW-VALUES ๐Ÿ™ˆ

The system command-line parameters can also be reached through the LINKAGE SECTION in the program where execution starts ๐ŸŒธ The data structure looks like this:

        linkage         section.
        01   argc       pic 999.
        01   argv.
         02  argv-table   occurs 1 to 100 times depending on argc.
          03 argv-element pointer.
        01   argv-string  pic x(100) .

and the code to access the third parameter looks like this:

        procedure division using by value argc by reference argv.
        set address of argv-string to argv-element(3)
        display argv-string

๐Ÿงš #line directive

The parser accepts lines in this form:

#line lineno โ€œfilenameโ€.

This sets the current line number to lineno and the current input filename to filename ๐Ÿ’– Preprocessors can use this directive to control the filename and line numbers reported in error messages and in the debugger ๐Ÿ”ฅ

๐Ÿ’œ SELECT ... ASSIGN TO

In the phrase:

ASSIGN TO filename

filename can be in quotes or not ๐Ÿ‘€ If it's quoted, it represents a filename as the operating system knows it. If it's unquoted, it names either a data element or an environment variable that contains the name of a file. If filename matches the name of a data element, that element gets used. If not, resolving filename gets deferred until runtime, and at that point the name has to be in the program's environment ๐ŸŒˆ

โœจ ISO COBOL Implementation Status โœจ

๐Ÿ’… USAGE Data Types

okay so gcobol supports these USAGE IS clauses, bestie ๐Ÿ’–

  • INDEX โ€” for when you need an index into a table ๐Ÿ“‹
  • POINTER โ€” for variables that hold the address of an external function, a PROGRAM-ID, or a data item. You assign to them with the SET statement ๐Ÿงš
  • BINARY, COMP, COMPUTATIONAL, COMP-4, COMPUTATIONAL-4 โ€” big-endian integer, 1 to 16 bytes, sized by the PICTURE ๐Ÿ”ฅ
  • COMP-1, COMPUTATIONAL-1, FLOAT-BINARY-32 โ€” IEEE 754 single-precision floating point, 4 bytes, handled by the hardware ๐Ÿฆ‹
  • COMP-2, COMPUTATIONAL-2, FLOAT-BINARY-64 โ€” IEEE 754 double-precision floating point, 8 bytes, also handled by the hardware ๐Ÿ’œ
  • COMP-3, COMPUTATIONAL-3, PACKED-DECIMAL โ€” currently unimplemented ๐Ÿ’€
Heads up, these three are not implemented yet, so don't build your whole life around COMP-3 just yet.
  • COMP-5, COMPUTATIONAL-5 โ€” little-endian integer, 1 to 16 bytes, sized by the PICTURE โœจ
  • FLOAT-BINARY-128, FLOAT-EXTENDED โ€” 128-bit floating point, per IEEE 754 ๐ŸŒˆ

gcobol supports the ISO integer BINARY-<type> types, and most of them are just aliases for COMP-5. It's giving organized ๐ŸŽ€

COMP-5        Compatible
Picture       BINARY Type        Bytes   Value
              BINARY-CHAR        1       0 โ€” 256
              [UNSIGNED]
S9(1...4)     BINARY-CHAR        1       -128 โ€” +127
              SIGNED
 9(1...4)     BINARY-SHORT       2       0 โ€” 65535
              [UNSIGNED]
S9(1...4)     BINARY-SHORT       2       -32768 โ€” +32767
              SIGNED
 9(5...9)     BINARY-LONG        4       0 โ€” 4,294,967,295
              [UNSIGNED]
S9(5...9)     BINARY-LONG        4       -2,147,483,648 โ€”
              SIGNED                     +2,147,483,647
 9(10...18)   BINARY-LONG-LONG   8       0 โ€”
              [UNSIGNED]                 18,446,744,073,709,551,615
S9(10...18)   BINARY-LONG-LONG   8       -9,223,372,036,854,775,808
              SIGNED                     โ€”
                                         +9,223,372,036,854,775,807

These define a size in bytes, so you cannot use them with a PICTURE clause ๐Ÿ™…โ€โ™€๏ธ Per the ISO standard, SIGNED is the default for the BINARY-type aliases.

All computation, both integer and floating point, is done using 128-bit intermediate forms. Math with main character energy ๐Ÿ‘‘

๐ŸŒธ Environment Names

In gcobol, DISPLAY UPON is the one doing the mapping:

DISPLAY UPON

It maps SYSOUT and STDOUT to standard output, and SYSPUNCH, SYSPCH and STDERR to standard error ๐Ÿ“ฃ

๐ŸŽ€ Exit Status

gcobol supports the ISO syntax for handing an exit status back to the operating system:

STOP RUN [WITH] {NORMAL | ERROR} [STATUS] status

It also supports the IBM syntax, which uses the RETURN-CODE register. The vibe is very "old school but make it work" ๐Ÿ™ˆ

MOVE ZERO TO RETURN-CODE.
GOBACK.

The RETURN-CODE register is defined as a 4-byte binary integer. ๐Ÿ‘


๐Ÿงš COMPILER-DIRECTING FACILITY

The CDF should be used with caution because no comprehensive test suite has been identified. Be careful out here, bestie ๐Ÿ˜ญ

๐Ÿฆ‹ CDF Text Manipulation

The COPY statement looks like this:

COPY copybook [OF|BY library] [REPLACING ...]

So if copybook is a literal, it's treated as a literal filename, and that file may or may not exist ๐Ÿ“„ If copybook is a COBOL word instead, gcobol first checks for an environment variable with that same name. If it finds one, it uses the contents of that variable as the name of the copybook file. If that file doesn't exist, it keeps looking for a file with one of these names, in this order:

  • copybook (literally)
  • copybook.cpy
  • copybook.CPY
  • copybook.cbl
  • copybook.CBL
  • copybook.cob
  • copybook.COB

It checks the same directory as the source code file first, then any copybook-path you set with the -I option. A copybook-path can be a colon-separated list, just like the shell's PATH variable. You can pass -I multiple times on the command line, and each new path gets added onto the ones before it. Relative paths (the ones without a leading /) are searched relative to the compiler's current working directory. ๐Ÿ—บ๏ธ

For example:

-I /usr/local/include:include

This searches the directory where the COBOL program lives first, then /usr/local/include, and finally an include subdirectory of the directory you invoked gcobol from ๐Ÿงญ

For the REPLACING phrase, both the modern pseudo-text form and the COBOL/85 form are recognized. The older forms are the ones used in the NIST CCVS/85 test suite, so they're still around for a reason ๐Ÿซถ

gcobol supports the full ISO REPLACE syntax:

REPLACE ...

๐ŸŒˆ CDF Directives

Here's the directive lineup. Slay the whole list ๐Ÿ’…

>>DEFINE

>>DEFINE name AS {expression | PARAMETER} [OVERRIDE]

This defines name as a compilation variable with the value expression. If name was already defined, you need OVERRIDE, or the directive is invalid. AS PARAMETER is accepted, but it has no effect in gcobol ๐Ÿ™ƒ

>>DEFINE name AS OFF

This releases the definition of name, so using it after that is invalid ๐Ÿšซ

>>IF

>>IF cce text [>>ELSE alt-text] >>END-IF

This evaluates cce, a constant conditional expression, for conditional compilation. If cce is a name, you can define it with the -D command-line parameter. If it's true, the COBOL text gets compiled. If it's false, alt-text gets compiled instead, if you included one. [IS [NOT]] DEFINED is supported. Boolean literals are not supported ๐Ÿšซโœจ

>>EVALUATE

Not implemented ๐Ÿ’€

>>CALL-CONVENTION

>>CALL-CONVENTION convention

convention can be one of:

  • COBOL โ€” standard COBOL case-insensitive symbol-name matching. For CALL โ€œnameโ€, the compiler renders name in lowercase ๐Ÿ”ค
  • C โ€” case-sensitive symbol-name matching. The CALL target isn't changed at all, it's used verbatim ๐ŸŽฏ
  • VERBATIM โ€” an alias for >>CALL-CONVENTION C ๐Ÿฆ‹

>>COBOL-WORDS

>>COBOL-WORDS EQUATE keyword WITH alias

This makes alias a synonym for keyword ๐Ÿ‘ฏโ€โ™€๏ธ

>>COBOL-WORDS UNDEFINE keyword

This removes keyword from the COBOL grammar. If a program uses it, the compiler will throw a syntax error ๐Ÿšจ

>>COBOL-WORDS SUBSTITUTE keyword BY new-word

This deletes keyword as a keyword and replaces it with new-word. After that, keyword can be used as a user-defined word ๐Ÿ”

>>COBOL-WORDS RESERVE new-word

This treats new-word as a COBOL keyword. The program can't use it at all, either as a keyword or as a user-defined word ๐Ÿ”’

>>DISPLAY

>>DISPLAY string ...

This writes string to standard error as a warning message โš ๏ธ

>>SOURCE

>>SOURCE format

format can be one of:

  • FIXED โ€” the source follows the COBOL fixed-form reference format, with unlimited line length ๐Ÿ“
  • FREE โ€” the source follows the COBOL free-form reference format. A โ€˜*โ€™ at the beginning of a line is recognized as a comment ๐Ÿ’ฌ

Not-yet-real directives

These are all not implemented yet, so they're just vibes for now ๐Ÿ‘ป

  • >>FLAG-02 โ€” Not implemented.
  • >>FLAG-85 โ€” Not implemented.
  • >>FLAG-NATIVE-ARITHMETIC โ€” Not implemented.
  • >>LEAP-SECOND โ€” Not implemented.
  • >>LISTING โ€” Not implemented.
  • >>PAGE โ€” Not implemented.
  • >>PROPAGATE โ€” Not implemented.

>>PUSH and >>POP

>>PUSH directive
>>POP directive

With PUSH, you push the CDF state onto a stack. With POP, you go back to the prior pushed state ๐Ÿ“š The directive can be one of: CALL-CONVENTION, COBOL-WORDS, DEFINE, SOURCE FORMAT, or TURN.

>>TURN

>>TURN [ec [file ...] ...] CHECKING {[ON] [[WITH] LOCATION] | OFF}

This enables the exception condition ec, or disables it if you use OFF. You can optionally tie ec to the file connectors file ๐Ÿ”Œ If you include LOCATION, gcobol reports at runtime the source filename and line number of the statement that set off the exception condition ๐Ÿ“

๐Ÿ’œ Feature-set Variables

Some command-line options affect CDF feature-set variables that are special to gcobol. You can set and test them using >>DEFINE and >>IF. They're easy to spot because they start with a %, which isn't valid in a COBOL identifier anyway ๐Ÿ‘€

  • %EBCDIC-MODE โ€” set by -finternal-ebcdic.
  • %64-BIT-POINTER โ€” implied by -dialect ibm.

To set a feature-set variable, use:

>>SET feature [AS] {ON | OFF}
If feature is %EBCDIC-MODE, the directive must appear before PROGRAM-ID. Order matters, bestie ๐Ÿ™

To test a feature-set variable, use:

>>IF feature DEFINED

๐Ÿ“ Intrinsic functions

gcobol implements all the intrinsic functions defined by ISO/IEC 1989:2023, plus a few extras. They're lined up alphabetically below ๐Ÿญ

ABS ACOS ANNUITY ASIN ATAN
BASECONVERT BIT-OF BIT-TO-CHAR BOOLEAN-OF-INTEGER BYTE-LENGTH
CHAR CHAR-NATIONAL COMBINED-DATETIME CONCAT CONVERT COS CURRENT-DATE
DATE-OF-INTEGER DATE-TO-YYYYMMDD DAY-OF-INTEGER DAY-TO-YYYYDDD DISPLAY-OF
E EXCEPTION-FILE EXCEPTION-FILE-N EXCEPTION-LOCATION EXCEPTION-LOCATION-N EXCEPTION-STATEMENT EXCEPTION-STATUS EXP EXP10
FACTORIAL FIND-STRING FORMATTED-CURRENT-DATE FORMATTED-DATE FORMATTED-DATETIME FORMATTED-TIME FRACTION-PART
HEX-OF HEX-TO-CHAR HIGHEST-ALGEBRAIC
INTEGER INTEGER-OF-BOOLEAN INTEGER-OF-DATE INTEGER-OF-DAY INTEGER-OF-FORMATTED-DATE INTEGER-PART
LENGTH LOCALE-COMPARE LOCALE-DATE LOCALE-TIME LOCALE-TIME-FROM-SECONDS LOG LOG10 LOWER-CASE LOWEST-ALGEBRAIC
MAX MEAN MEDIAN MIDRANGE MIN MOD MODULE-NAME
NATIONAL-OF NUMVAL NUMVAL-C NUMVAL-F ORD
ORD-MAX ORD-MIN
PI PRESENT-VALUE
RANDOM RANGE REM REVERSE
SECONDS-FROM-FORMATTED-TIME SECONDS-PAST-MIDNIGHT SIGN SIN SMALLEST-ALGEBRAIC SQRT STANDARD-COMPARE STANDARD-DEVIATION SUBSTITUTE SUM
TAN TEST-DATE-YYYYMMDD TEST-DAY-YYYYDDD TEST-FORMATTED-DATETIME TEST-NUMVAL TEST-NUMVAL-C TEST-NUMVAL-F TRIM
ULENGTH UPOS UPPER-CASE USUBSTR USUPPLEMENTARY UUID4 UVALID UWIDTH
VARIANCE
WHEN-COMPILED
YEAR-TO-YYYY

๐Ÿ’– Binary floating point DISPLAY

How DISPLAY presents binary floating point numbers depends on the value. It's giving "the number decides its own outfit" ๐Ÿ‘—

  • If a value has six or fewer digits to the left of the decimal point, it's shown like 123456.789....
  • If a value is less than 1 and has no more than three zeroes to the right of the decimal point, it's shown like 0.0001234....
  • Otherwise, you get exponential notation, like 1.23456E+7 ๐Ÿš€

In all cases, trailing zeroes on the right of the number get removed from the displayed value. โœจ

  • COMP-1 โ€” displayed with 9 decimal digits ๐Ÿ’–
  • COMP-2 โ€” displayed with 17 decimal digits โœจ
  • FLOAT-EXTENDED โ€” displayed with 36 decimal digits ๐ŸŒˆ

Those digit counts are lowkey giving IEEE 754 energy ๐Ÿค“, since they match the requirements for information interchange. As one example, check out the description for COMP-2 binary64 values (per Wikipedia) ๐Ÿ“–.

If an IEEE 754 double-precision number gets converted to a decimal string with at least 17 significant digits, and then converted back to double-precision representation, the final result must match the original number. Iconic, right? โœจ

17 digits was picked so that DISPLAY shows the contents of a COMP-2 variable without hiding any information. No secrets, no cap ๐Ÿ’…


๐Ÿฆ‹ Binary floating point MOVE ๐Ÿฆ‹

Okay, so during a MOVE statement, a floating-point value may be truncated ๐Ÿ˜ญ. It's not unusual for Numeric Display values to get altered when they get moved through a floating-point value.

This program:

    01 PICV999 PIC 9999V999.
    01 COMP2 COMP-2.
   PROCEDURE DIVISION.
    MOVE 1.001 to PICV999
    MOVE PICV999 TO COMP2
    DISPLAY "The result of MOVE " PICV999 " TO COMP2 is   " COMP2
    MOVE COMP2 to PICV999
    DISPLAY "The result of MOVE COMP2    TO PICV999 is " PICV999

generates this result:

    The result of MOVE 0001.001 TO COMP2 is   1.00099999999999989
    The result of MOVE COMP2    TO PICV999 is 0001.000

However, the internal implementation can produce results that might seem surprising ๐Ÿ™ˆ:

    The result of MOVE 0055.110 TO COMP2 is   55.1099999999999994
    The result of MOVE COMP2    TO PICV999 is 0055.110

The tea behind this inconsistency is how gcobol stores and converts numbers โ˜•. Converting the floating-point value to the numeric display value 0055110 is done by multiplying 55.109999... by 1,000 and then truncating the result to an integer. And it turns out that even though 55.11 can't be represented in floating-point as an exact value, the product of the multiplication, 55110, is an exact value ๐Ÿคฏ.

If you need conversions to have predictable results, you'll want to apply rounding, which you can do with an arithmetic statement ๐ŸŽ€:

    MOVE 1.001 to PICV999
    MOVE PICV999 TO COMP2
    DISPLAY "The result of MOVE " PICV999 " TO COMP2 is   " COMP2
    MOVE COMP2 to PICV999
    DISPLAY "The result of MOVE COMP2    TO PICV999 is " PICV999
    ADD COMP2 to ZERO GIVING PICV999 ROUNDED
    DISPLAY "The result of ADD COMP2 to ZERO GIVING PICV999 ROUNDED is " PICV999
    The result of MOVE 0001.001 TO COMP2 is   1.00099999999999989
    The result of MOVE COMP2    TO PICV999 is 0001.000
    The result of ADD COMP2 to ZERO GIVING PICV999 ROUNDED is 0001.001

๐ŸŒˆ Binary floating point computation ๐ŸŒˆ

gcobol tries to do internal computations with binary integers whenever possible ๐Ÿง . So simple arithmetic between binary values and numeric display values wraps up with binary intermediate results.

If a floating-point value gets included in the mix of variables in a calculation, then the intermediate result becomes a 128-bit floating-point value ๐Ÿ”ฅ.


๐Ÿšซ A warning about binary floating point comparison ๐Ÿšซ

The cardinal rule when comparing floating-point values: Never, ever, test for equality. It's just not worth the hassle ๐Ÿ’€.

For example:

    WORKING-STORAGE SECTION.
    01 COMP1 COMP-1 VALUE 555.11.
    01 COMP2 COMP-2 VALUE 555.11.
   PROCEDURE DIVISION.
    DISPLAY "COMPARE " COMP1 " with " COMP2
    IF COMP1 EQUAL COMP2 DISPLAY "Equal" ELSE DISPLAY "Not equal" END-IF

    MOVE COMP1 to COMP2
    DISPLAY "COMPARE " COMP1 " with " COMP2
    IF COMP1 EQUAL COMP2 DISPLAY "Equal" ELSE DISPLAY "Not equal" END-IF

the results:

    COMPARE 555.1099854 with 555.110000000000014
    Not equal
    COMPARE 555.1099854 with 555.1099853515625
    Equal

Why? Again, it's all about the internals of gcobol ๐Ÿ”. When differently sized floating-point values need to be compared, they get converted to 128-bit floats first. And it turns out that when a COMP1 is moved to a COMP2, and they're both converted to FLOAT-EXTENDED, the two resulting values are (probably) equal ๐Ÿคทโ€โ™€๏ธ.

Avoid testing for equality unless you really know what you're doing and you really test the code. And then avoid it anyway ๐Ÿ˜ค.

Finally, it is observably the case that the gcobol implementations of floating-point conversions and comparisons don't precisely match the behavior of other COBOL compilers ๐Ÿ™ƒ.

You have been warned. โš ๏ธ

๐ŸŒธ ENVIRONMENT ๐ŸŒธ

  • COBPATH โ€” If this is defined, it specifies the directory paths the gcobol runtime library, libgcobol.so, uses to locate shared objects ๐Ÿงš. Like LD_LIBRARY_PATH, it can hold several directory names separated by a colon (โ€˜:โ€™). COBPATH gets searched first, followed by LD_LIBRARY_PATH.
    • Each directory gets searched for files whose name ends in โ€˜.soโ€™. For each one of those files, dlopen(3) is attempted and, if successful, dlsym(3). No relationship is defined between the symbol's name and the filename ๐Ÿค”.
    • Without COBPATH, binaries produced by gcobol behave the way you'd expect from any program compiled with gcc ๐Ÿ’…. Any shared objects the program needs get mentioned on the command line with a -llibrary option, and they're found by following the executable's RPATH, or otherwise per the configuration of the runtime linker, ld.so(8).
  • UPSI โ€” COBOL defines a User Programmable Status Indicator (UPSI) switch ๐ŸŽ›๏ธ. In gcobol, the settings are denoted UPSI-0 through UPSI-7, where 0-7 indicates a bit position. The value of the UPSI switches comes from the UPSI environment variable, whose value is a string of up to eight 1's and 0's. The first character represents the value of UPSI-0, and missing values are assigned 0. For example, UPSI=1000011 in the environment sets bits 0, 5, and 6 on, which means that UPSI-0, UPSI-5, and UPSI-6 are on โœจ.
  • GCOBOL_TEMPDIR โ€” This one causes any temporary files created during CDF processing to be written to a file whose name is specified in the value of GCOBOL_TEMPDIR. If the value is just โ€œ/โ€, the effect is different: each copybook read is reported on standard error ๐Ÿ“ฃ. It's meant to help diagnose mysterious copybook errors ๐Ÿ•ต๏ธโ€โ™€๏ธ.

๐Ÿ“ FILES ๐Ÿ“

Executables produced by gcobol require the runtime support library libgcobol, which is provided both as a static library and as a shared object ๐Ÿ“ฆ.

๐Ÿฆ‹ COMPATIBILITY ๐Ÿฆ‹

The ISO standard leaves the default file organization up to the implementation. In gcobol, the default is SEQUENTIAL ๐Ÿ“.

๐Ÿงš On-Disk Format ๐Ÿงš

Any ability to use files produced by other COBOL compilers, or for those compilers to use files produced by gcobol, is the product of luck and intuition ๐Ÿ€. Various compilers interpret the ISO standard differently, and the standard's text is not always definitive ๐Ÿ“œ.

For ORGANIZATION IS LINE SEQUENTIAL files (explicitly or by default), gcobol, absent specific direction, produces an ordinary Linux text file ๐Ÿง. For each WRITE, the data gets written, followed by an ASCII NL (hex 0A) character. On READ, the record is read up to the size of the specified record or NL, whichever comes first. The NL is not included in the data brought into the record buffer; it only serves as an on-disk record-termination marker. So SEQUENTIAL and LINE SEQUENTIAL files work the same way: the COBOL program never sees the record terminator ๐Ÿ‘€.

When READ and WRITE are used with ADVANCING, though, the plot twists ๐ŸŒ€. If ADVANCING is used with LINE SEQUENTIAL files, it is honored by gcobol.

Other compilers may not do likewise. According to ISO, in WRITE (14.9.47.3 General rules), ADVANCING is ignored for files for which โ€œthe physical file does not support vertical positioningโ€. It further states that, in the absence of ADVANCING, WRITE proceeds as if โ€œas if the user has specified AFTER ADVANCING 1 LINEโ€. Some other implementations interpret that to mean that the first WRITE to a LINE SEQUENTIAL file results in a leading NL on the first line, and no trailing NL on the last line. Some even furthermore prohibit the use of ADVANCING with LINE SEQUENTIAL files ๐Ÿ™…โ€โ™€๏ธ.

๐Ÿ“š STANDARDS ๐Ÿ“š

The reference standard for gcobol is ISO/IEC 1989:2023 ๐ŸŽ“.

  • If gcobol compiles code consistent with that standard, the resulting program should execute correctly; any other result is a bug ๐Ÿ›.
  • If gcobol compiles code that doesn't comply with that standard, but runs correctly according to some other specification, that represents a non-standard extension. One day, the -pedantic option will produce diagnostic messages for such code ๐Ÿ”œ.
  • If gcobol rejects code consistent with that standard, that represents an aspect of COBOL that is (or is not) on the To Do list ๐Ÿ“. If you'd like to see it compile, please get in touch with the developers ๐Ÿ’Œ.

๐ŸŒŸ Status of NIST COBOL Compiler Verification Suite ๐ŸŒŸ

  • NC โ€” 100% โ€” Nucleus
  • SQ โ€” 100% โ€” Sequential I/O
  • RL โ€” 100% โ€” Relative I/O
  • IX โ€” 100% โ€” Indexed I/O
  • IC โ€” 100% โ€” Inter-Program Communication
  • ST โ€” 100% โ€” Sort-Merge
  • SM โ€” 100% โ€” Source Text Manipulation RW \n Report Writer
  • CM โ€” (no status listed) โ€” Communication
  • DB โ€” "to do?" โ€” Debug
  • SG โ€” (no status listed) โ€” Segmentation
  • IF โ€” 100% โ€” Intrinsic Function

Where gcobol passes 100% of the tests in a module, we exclude the (few) tests for obsolete features. The authors regard features that were obsolete in 1985 as well and truly obsolete today, so they didn't implement them ๐Ÿฅ€.

๐ŸŒ™ Notable deferred features ๐ŸŒ™

CCVS-85 modules not marked above with any status (CM and SG) are on the โ€œhard maybeโ€ list ๐Ÿคทโ€โ™€๏ธ. That means they're waiting on an interested party with real code that uses the feature.

gcobol does not implement Report Writer or Screen Section ๐Ÿ™…โ€โ™€๏ธ.

๐Ÿš€ Beyond COBOL/85 ๐Ÿš€

gcobol increasingly implements ISO/IEC 1989:2023 ๐Ÿ“ˆ. For example, DECLARATIVES is not tested by CCVS-85, but gcobol implements it anyway. Similarly, Exception Conditions weren't defined in 1985, and gcobol contains a growing number of them ๐Ÿ’ซ.

The authors are well aware that a complete, pure COBOL-85 compiler won't compile most existing COBOL code ๐Ÿ˜…. Every vendor offered (and still offers) extensions, and most environments rely on a variety of preprocessors and ancillary systems defined outside the standard. The express goal of adding an ISO COBOL front-end to GCC is to establish a foundation on which any needed extensions can be built ๐Ÿ—๏ธ๐Ÿ’œ.

โœจ HISTORY โœจ

Okay so, COBOL the language is literally older than you, bestie ๐Ÿ’€ ๐Ÿฆ‹ Free COBOL compilers, to the author's knowledge, first started showing up around 2000. Right around then, the cobolforgcc project (https://cobolforgcc.sourceforge.net/) had some real success ๐ŸŒธ It was never officially merged into GCC though, which is a whole plot twist ๐Ÿ˜ญ

Then came gcobol, started by COBOLworx (https://www.cobolworx.com/) in the fall of 2021 โœจ In December 2022 the project announced a complete implementation of the core language features. Iconic behavior, honestly ๐Ÿ‘‘


โœจ AUTHORS โœจ

The two brains behind this compiler, and what each of them handles ๐Ÿ’œ

  • James K. Lowden (jklowden@cobolworx.com) is responsible for the parser ๐Ÿ”ฅ
  • Robert Dubner (rdubner@cobolworx.com) is responsible for producing the GIMPLE tree, which is the input to the GCC back-end ๐Ÿงš

โœจ CAVEATS โœจ

Okay, real talk, this section is important so pay attention ๐Ÿ™ˆ

  • gcobol has only been tested on x64 and Apple M1 processors, and only while running Linux in 64-bit mode ๐Ÿ’…
  • The I/O support has not been extensively tested, and it doesn't implement or emulate many features tied to VSAM and other mainframe subsystems. LINE-SEQUENTIAL files are ordinary text files that you can happily poke at with standard utilities ๐Ÿซถ But INDEXED and RELATIVE files produced by gcobol are not compatible with those from any other COBOL compiler. โš ๏ธ Enhancements to the I/O support will be readily available to the paying customer. ๐Ÿ’ธ
โš ๏ธ Bestie, if you're relying on INDEXED or RELATIVE files to play nice with other compilers, don't. It's giving incompatibility ๐Ÿ’€

That's the whole page, bestie! ๐ŸŽ€ This manual page came from Linux, dated February 2025, and it's the GCOBOL(1) page. Now go forth and compile something iconic โœจ๐Ÿ’–