GnuCOBOL -fdec - DEC/VSI COBOL Language Extensions
Overview
-fdec is a compatibility mode built into Sector7's GnuCOBOL compiler that lets DEC and VSI COBOL source code, written for OpenVMS, compile and run on Linux. It recognises the VMS-specific syntax, storage rules, and status conventions those programs rely on, so applications that call OpenVMS RTL routines or depend on RMS-style file handling can be rebuilt without rewriting the source.
The flag is a single, explicit gate: with -fdec off, every extension it enables becomes a compile-time error rather than a silent reinterpretation, so a standard COBOL program compiles identically whether or not the flag is used. Where Linux cannot reproduce an OpenVMS-specific mechanism exactly, such as link-time symbol resolution or VAX floating-point formats, the compiler takes the practical Linux equivalent and documents the difference instead of pretending to be VMS.
<div class="s7-tech-embed" data-gnucoboldec-body-embed="1" data-technical-mega-embed="1" lang="en"><h2 id="architecture">Architecture and components</h2><p>
Under <code>-fdec</code>, a compiled program is wired across four layers. Turning the flag
off does not remove functionality gradually: every extension below becomes a compile-time
error, and a standard COBOL program compiles identically whether or not the flag is used.
</p><div class="table-wrapper"><table><thead><tr><th>OpenVMS equivalent</th><th>Linux component</th><th>Role</th></tr></thead><tbody><tr><td>VSI COBOL compiler front end</td><td><code>cobc</code> with <code>-fdec</code></td><td>Parses VSI syntax and applies VSI storage, naming, and status semantics.</td></tr><tr><td>OpenVMS RTL condition macros</td><td>Low-bit <code>IS SUCCESS</code> / <code>IS FAILURE</code> support in the runtime</td><td>Tests the OpenVMS success/failure convention at runtime.</td></tr><tr><td>OpenVMS image linker symbol resolution</td><td>DEC-spelling fallback resolver</td><td>Falls back to the DEC-style symbol spelling so a standard-built caller can still find an <code>-fdec</code>-built routine.</td></tr><tr><td>RMS (Record Management Services)</td><td>External file handler</td><td>Translates COBOL file operations into calls Sector7's VX/RMS understands.</td></tr><tr><td>RMS on OpenVMS</td><td>VX/RMS (Sector7's RMS-on-Linux runtime)</td><td>Performs the actual file opens, reads, writes, and key lookups.</td></tr><tr><td>VMS symbolic status constants</td><td>Built-in constant table, 11,388 entries</td><td>Resolves <code>VALUE IS EXTERNAL name</code> constants at compile time instead of at link time.</td></tr><tr><td>VMS RTL / system-service call signatures</td><td>Built-in routine table, 565 routines</td><td>Pads call arguments to each routine's expected count and remaps a handful of item-list services.</td></tr></tbody></table></div><h6>How a routine call resolves</h6><p>
For a program calling an OpenVMS RTL routine, for example
<code>CALL "LIB$PUT_OUTPUT" USING BY DESCRIPTOR MSG RETURNING ST</code>, the compiler works
through the call in a fixed sequence:
</p><ol><li>Accepts the VMS-style routine name, the <code>BY DESCRIPTOR</code> call mode, and a <code>RETURNING</code> target.</li><li>Looks up the routine in the built-in arity table and pads the argument list to the count that routine expects. Supplying too many arguments is a hard compile error.</li><li>Emits each <code>BY DESCRIPTOR</code> argument as a 64-bit OpenVMS string descriptor.</li><li>Maps the routine's return value into the <code>RETURNING</code> / <code>GIVING</code> item if present, otherwise into <code>RETURN-CODE</code>.</li><li>Compiles <code>IS SUCCESS</code> / <code>IS FAILURE</code> tests against that status using the OpenVMS low-bit convention: bit 0 set means success.</li><li>If the routine being called was itself built with <code>-fdec</code>, its exported symbol uses the DEC spelling. The runtime's fallback resolver tries that spelling automatically, so callers do not need to know which mode built the callee.</li></ol><h6>How file I/O routes through RMS</h6><p>Any program that has files defaults to routing file I/O through VX/RMS:</p><ol><li>Every <code>OPEN</code>, <code>READ</code>, <code>WRITE</code>, <code>REWRITE</code>, <code>DELETE</code>, <code>START</code>, and <code>CLOSE</code> is handed to the external file handler.</li><li>The handler builds the record and key blocks VX/RMS expects and calls through to the underlying open, create, connect, get, put, update, delete, and find operations.</li><li>Each file's last RMS status is kept per file, ready to support the RMS status special registers.</li><li>Setting an explicit file-handler flag overrides the RMS default and switches file I/O back to the compiler's built-in file layer.</li></ol><h2 id="example">Example: calling an OpenVMS routine</h2><p>
This program calls an OpenVMS RTL routine by descriptor and checks the result with the
low-bit success and failure convention, no more code than a standard <code>CALL</code>
needs:
</p>
<pre><span class="kw">IDENTIFICATION DIVISION.</span>
<span class="kw">PROGRAM-ID.</span> LIB-PUT-OUTPUT-DEMO.
<span class="kw">DATA DIVISION.</span>
<span class="kw">WORKING-STORAGE SECTION.</span>
01 MESSAGE-TEXT PIC X(42)
VALUE <span class="str">"Hello from COBOL via LIB$PUT_OUTPUT"</span>.
01 RETURN-STATUS PIC S9(9) COMP VALUE ZERO.
<span class="kw">PROCEDURE DIVISION.</span>
<span class="kw">CALL</span> <span class="str">"LIB$PUT_OUTPUT"</span>
<span class="kw">USING BY DESCRIPTOR</span> MESSAGE-TEXT
<span class="kw">RETURNING</span> RETURN-STATUS
<span class="kw">END-CALL</span>.
<span class="kw">IF</span> RETURN-STATUS <span class="kw">IS FAILURE</span>
<span class="kw">DISPLAY</span> <span class="str">"LIB$PUT_OUTPUT failed, status "</span> RETURN-STATUS
<span class="kw">END-IF</span>.
<span class="kw">GOBACK</span>.</pre>
<p>Compiled with:</p>
<pre>cobc -fdec prog.cob</pre>
<h2 id="language-extensions">Language extensions</h2><p><code>-fdec</code> activates a set of reserved words and syntax forms that only carry VSI
meaning when the flag is on. With the flag off, using any of them is a compile error
rather than a silent reinterpretation.
</p><div class="table-wrapper"><table><thead><tr><th>Keyword</th><th>Meaning under -fdec</th></tr></thead><tbody><tr><td><code>DESCRIPTOR</code></td><td><code>CALL ... USING BY DESCRIPTOR</code> call mode.</td></tr><tr><td><code>POINTER-64</code></td><td><code>USAGE POINTER-64</code> on 64-bit-pointer builds.</td></tr><tr><td><code>SUCCESS</code> / <code>FAILURE</code></td><td><code>SET ... TO SUCCESS/FAILURE</code>, <code>... IS SUCCESS/FAILURE</code>.</td></tr><tr><td><code>IDENT</code></td><td><code>PROGRAM-ID. name WITH IDENT "literal"</code>, a module version string.</td></tr><tr><td><code>REGARDLESS</code></td><td><code>READ</code> / <code>START ... REGARDLESS [OF LOCK]</code>.</td></tr><tr><td><code>PRIOR</code></td><td><code>READ ... PRIOR</code>, equivalent to <code>READ PREVIOUS</code>.</td></tr><tr><td><code>LOCK-HOLDING</code>, <code>DEFERRED-WRITE</code>, <code>EXTENSION</code>, <code>FILL-SIZE</code>, <code>MASS-INSERT</code>, <code>PREALLOCATION</code>, <code>PRINT-CONTROL</code>, <code>WINDOW</code></td><td><code>APPLY</code> clauses carrying RMS tuning hints.</td></tr><tr><td><code>ALLOWING</code>, <code>OTHERS</code>, <code>READERS</code>, <code>UPDATERS</code>, <code>WRITERS</code></td><td>Sharing and locking modifiers on <code>OPEN</code> / <code>READ</code> / <code>WRITE</code> / <code>REWRITE</code> / <code>START</code>.</td></tr></tbody></table></div><p>
Also recognised, without adding new reserved words: <code>$</code> inside a user-defined
word (not as the first character), <code>REFERENCE OF</code> as an equivalent to
<code>ADDRESS OF</code>, <code>VALUE IS EXTERNAL name</code>, <code>VALUE IS REFERENCE
data-name</code> or a literal, <code>GIVING</code> on <code>PROCEDURE DIVISION</code>, and
logical-name mnemonics in <code>SPECIAL-NAMES</code> bound to environment name, environment
value, and argument number or value.
</p><h2 id="feature-reference">Feature reference</h2><h6>Routine and call interop</h6><div class="table-wrapper"><table><thead><tr><th>Feature</th><th>Behaviour under -fdec</th></tr></thead><tbody><tr><td><code>CALL ... USING BY DESCRIPTOR</code></td><td>Emits a 64-bit OpenVMS string descriptor per argument. Arguments must be alphanumeric. Caller-side only.</td></tr><tr><td>Routine arity padding</td><td>Pads the call's argument list to the routine's expected count using the built-in 565-routine table. A handful of item-list services are remapped to their local equivalents.</td></tr><tr><td><code>USAGE POINTER-64</code></td><td>Accepted on 64-bit-pointer builds, a hard error otherwise.</td></tr><tr><td><code>PROCEDURE DIVISION GIVING item</code></td><td>VSI return-value semantics: the named item holds the routine's return value on exit. The item can live in working storage or linkage.</td></tr><tr><td><code>CALL GIVING</code> / <code>RETURN-CODE</code> mapping</td><td>The called routine's return value lands in the <code>GIVING</code> item if present, otherwise in <code>RETURN-CODE</code>; interoperates with <code>IS SUCCESS</code> / <code>IS FAILURE</code>.</td></tr></tbody></table></div><h6>Status conditions</h6><div class="table-wrapper"><table><thead><tr><th>Feature</th><th>Behaviour under -fdec</th></tr></thead><tbody><tr><td><code>SET status TO SUCCESS</code> / <code>TO FAILURE</code></td><td>Sets the OpenVMS low-bit condition state (bit 0 set means success). Targets are validated as word or longword numeric items.</td></tr><tr><td><code>status IS SUCCESS</code> / <code>IS FAILURE</code></td><td>Compiles to a runtime low-bit test on the status item.</td></tr></tbody></table></div><h6>Data initialisation</h6><div class="table-wrapper"><table><thead><tr><th>Feature</th><th>Behaviour under -fdec</th></tr></thead><tbody><tr><td><code>VALUE IS EXTERNAL name</code></td><td>Initialises an integer item from a VMS symbolic constant. Hyphens and underscores are treated as equivalent, so <code>SS$-NORMAL</code> and <code>SS$_NORMAL</code> resolve the same way. Resolved from the built-in 11,388-entry table at compile time; an unknown name is a hard compile error, never a silent zero.</td></tr><tr><td><code>-fdec-constants=<file></code></td><td>Supplies additional application-level constants not in the built-in table. Accepts simple <code>NAME = value</code> lines. Checked before the built-in table, and can be repeated.</td></tr><tr><td><code>VALUE IS REFERENCE data-name</code></td><td>Initialises a pointer to the address of static data. The target may be declared later in the program.</td></tr><tr><td><code>VALUE IS REFERENCE numeric-literal</code></td><td>Initialises a pointer to a literal integer address.</td></tr><tr><td><code>SET pointer TO REFERENCE OF item</code></td><td>The VSI address-of spelling, equivalent to <code>ADDRESS OF</code>.</td></tr></tbody></table></div><h6>Storage and numeric model</h6><div class="table-wrapper"><table><thead><tr><th>Feature</th><th>Behaviour under -fdec</th></tr></thead><tbody><tr><td>Binary storage model</td><td><code>-fdec</code> implies word-sized <code>COMP</code> for 1 to 4 digits, longword for 5 to 9, and quadword for 10 to 18, with native (little-endian) byte order. Each part can be overridden explicitly.</td></tr><tr><td>Floating-point usages</td><td><code>COMP-1</code> is IEEE single precision, <code>COMP-2</code> is IEEE double precision, and <code>FLOAT-EXTENDED</code> is treated as an 8-byte synonym for <code>COMP-2</code>, matching the VSI usage rule.</td></tr></tbody></table></div><h6>Names and symbols</h6><div class="table-wrapper"><table><thead><tr><th>Feature</th><th>Behaviour under -fdec</th></tr></thead><tbody><tr><td><code>$</code> in user-defined words</td><td>Allowed anywhere except as the first character, so names like <code>SYS$TRNLNM</code> are valid.</td></tr><tr><td>Hyphen and underscore equivalence</td><td>In user-defined words, <code>_</code> and <code>-</code> fold together, so <code>C_NINE</code> and <code>C-NINE</code> are the same word. External names (<code>PROGRAM-ID</code>, and constant <code>CALL</code> / <code>ENTRY</code> / <code>CANCEL</code> names) encode a hyphen as an underscore in the exported symbol, matching VSI's own link-symbol spelling.</td></tr><tr><td><code>PROGRAM-ID. name WITH IDENT "literal"</code></td><td>A VSI module version string, validated as non-numeric text between 1 and 31 characters.</td></tr><tr><td>Logical-name mnemonics in <code>SPECIAL-NAMES</code></td><td>Lets <code>DISPLAY ... UPON</code> and <code>ACCEPT ... FROM</code> target environment name, environment value, and argument mnemonics. Off OpenVMS, logical names map to environment variables.</td></tr></tbody></table></div><h6>Control flow</h6><p><code>-fdec</code> turns on OSVS-style <code>PERFORM</code> range semantics by default,
matching the dynamic range behaviour described in the VSI reference material: a
<code>GO TO</code> between the start and end of a performed range, with multiple logical
paths back to the return point. This can be turned off explicitly for programs that need
standard <code>PERFORM</code> semantics instead.
</p><h2 id="file-io">File I/O through RMS</h2><p>
Programs with files default to routing every file operation through VX/RMS. This covers
sequential, line sequential, relative, and indexed organisation, including alternate keys
with duplicates and split keys. An explicit file-handler flag can switch a program back to
the compiler's own file layer.
</p><h6>Extended file I/O syntax</h6><p>Every clause below is a hard compile error without <code>-fdec</code>:</p>
<pre><span class="kw">INPUT-OUTPUT SECTION.</span>
<span class="kw">FILE-CONTROL.</span>
<span class="kw">SELECT</span> F1 <span class="kw">ASSIGN TO</span> <span class="str">"f1.dat"</span>
<span class="kw">ORGANIZATION INDEXED ACCESS DYNAMIC</span>
<span class="kw">RECORD KEY IS</span> SK = R1-A R1-B
<span class="kw">ALTERNATE RECORD KEY IS</span> R1-C <span class="kw">WITH DUPLICATES</span>.
<span class="kw">I-O-CONTROL.</span>
<span class="kw">APPLY LOCK-HOLDING ON</span> F1.
<span class="kw">APPLY DEFERRED-WRITE ON</span> F1.
<span class="kw">APPLY EXTENSION</span> 100 <span class="kw">ON</span> F1.
<span class="kw">APPLY PREALLOCATION</span> 500 <span class="kw">ON</span> F1.
<span class="kw">APPLY WINDOW</span> 7 <span class="kw">ON</span> F1.
<span class="kw">PROCEDURE DIVISION.</span>
<span class="kw">OPEN I-O</span> F1 <span class="kw">ALLOWING ALL</span>
<span class="kw">START</span> F1 <span class="kw">KEY IS</span> >= SK <span class="kw">REGARDLESS</span>
<span class="kw">READ</span> F1 <span class="kw">ALLOWING NO OTHERS KEY IS</span> SK <span class="kw">END-READ</span>
<span class="kw">READ</span> F1 <span class="kw">NEXT REGARDLESS OF LOCK END-READ</span>
<span class="kw">READ</span> F1 <span class="kw">PRIOR END-READ</span>
<span class="kw">REWRITE</span> R1 <span class="kw">ALLOWING UPDATERS END-REWRITE</span>
<span class="kw">UNLOCK</span> F1 <span class="kw">ALL RECORDS</span>
<span class="kw">CLOSE</span> F1
<span class="kw">STOP RUN.</span></pre>
<h6>Clause reference</h6><div class="table-wrapper"><table><thead><tr><th>Clause</th><th>Behaviour</th></tr></thead><tbody><tr><td><code>VALUE OF ID IS "x"</code> (FD)</td><td>Overrides the file spec given on <code>ASSIGN</code>.</td></tr><tr><td><code>APPLY LOCK-HOLDING ON f</code></td><td>Switches the file to manual lock mode, normally paired with <code>OPEN ALLOWING</code> / <code>READ REGARDLESS</code>.</td></tr><tr><td><code>APPLY DEFERRED-WRITE / EXTENSION n / FILL-SIZE / MASS-INSERT / PREALLOCATION n / WINDOW n / PRINT-CONTROL</code></td><td>Accepted as RMS tuning hints with a default-on warning; they have no effect on this build and can be silenced with a compiler flag.</td></tr><tr><td><code>READ f [NEXT/PRIOR] ... REGARDLESS [OF LOCK]</code></td><td>Reads while ignoring locks. <code>READ PRIOR</code> is equivalent to <code>READ PREVIOUS</code>.</td></tr><tr><td><code>READ/WRITE/REWRITE ... ALLOWING NO OTHERS / READERS / UPDATERS / WRITERS / ALL</code></td><td><code>NO OTHERS</code> takes a lock; <code>UPDATERS</code>, <code>WRITERS</code>, and <code>ALL</code> take no lock; <code>READERS</code> is treated as <code>NO OTHERS</code> with a warning.</td></tr><tr><td><code>UNLOCK f ALL RECORDS</code></td><td>Releases every lock held on the file.</td></tr></tbody></table></div><div class="callout"><strong>File-name and path rules.</strong> VX/RMS uppercases file names to match authentic
VMS behaviour (<code>cust.dat</code> becomes <code>CUST.DAT</code>), and it cannot address a
Unix path with a dot in any directory component, so programs need to run from dot-free
working directories. Unsupported operations never fail silently: they return a file status
and name the operation and file on the error stream.
</div><h2 id="compatibility">Compatibility with OpenVMS</h2><p>
Every item below is either fully working today or has a defined status. Where Linux
cannot reproduce an OpenVMS mechanism exactly, the difference is deliberate and documented
rather than silently approximated.
</p><div class="table-wrapper"><table><thead><tr><th>Item</th><th>Status</th></tr></thead><tbody><tr><td>Call by descriptor, routine arity padding, 64-bit pointers</td><td><span class="ac-live">live</span></td></tr><tr><td>VMS symbolic constants (11,388 entries) and constant file supplements</td><td><span class="ac-live">live</span></td></tr><tr><td>Pointer initialisation by reference and address-of</td><td><span class="ac-live">live</span></td></tr><tr><td>Success/failure condition handling, GIVING return values</td><td><span class="ac-live">live</span></td></tr><tr><td><code>$</code> in words, hyphen/underscore equivalence, module version strings</td><td><span class="ac-live">live</span></td></tr><tr><td>VSI binary storage model and IEEE float usages</td><td><span class="ac-live">live</span></td></tr><tr><td>OSVS-style <code>PERFORM</code> range</td><td><span class="ac-live">live</span></td></tr><tr><td>File I/O through VX/RMS, including indexed files and split keys</td><td><span class="ac-live">live</span></td></tr><tr><td>Extended file I/O syntax (<code>REGARDLESS</code>, <code>ALLOWING</code>, <code>VALUE OF ID</code>, <code>APPLY</code> hints)</td><td><span class="ac-live">live</span></td></tr><tr><td>RMS status special registers</td><td><span class="ac-v1">v1 soon</span></td></tr><tr><td>Sharing mode wired through to the file control descriptor on <code>OPEN ALLOWING</code></td><td><span class="ac-v1">v1 soon</span></td></tr><tr><td>Multiple <code>APPLY</code> phrases in a single clause</td><td><span class="ac-v1">v1 soon</span></td></tr><tr><td>Full partial-spec merge on <code>VALUE OF ID</code></td><td><span class="ac-v1">v1 soon</span></td></tr><tr><td>Callee-side <code>PROCEDURE DIVISION USING BY DESCRIPTOR</code></td><td><span class="ac-v2">v2</span></td></tr><tr><td>19 to 31 digit octaword <code>COMP</code></td><td><span class="ac-no">out of scope</span></td></tr><tr><td>VAX floating-point bit-pattern emulation</td><td><span class="ac-no">out of scope</span></td></tr><tr><td>Embedded SQL and repository features</td><td><span class="ac-no">out of scope, handled separately by VX/SQL-COBOL</span></td></tr></tbody></table></div><h6>Deliberate differences from OpenVMS</h6><div class="table-wrapper"><table><thead><tr><th>Difference</th><th>Reason</th></tr></thead><tbody><tr><td><code>VALUE IS EXTERNAL</code> resolves at compile time, not link time</td><td>There is no OpenVMS linker on Linux, so constants come from the built-in table instead.</td></tr><tr><td>The word/longword-only restriction on <code>VALUE EXTERNAL</code> is not enforced</td><td>Any numeric integer item is accepted, a deliberately permissive superset.</td></tr><tr><td>No VAX floating-point emulation</td><td>VAX-format float data is converted upstream, so the compiler only ever sees IEEE values.</td></tr><tr><td>External names encode a hyphen as a single underscore, not two</td><td>Matches the VSI link-symbol spelling exactly, and the runtime resolver bridges both spellings automatically.</td></tr><tr><td>File names are uppercased and paths cannot contain dots</td><td>Carries over authentic VMS RMS file-naming rules.</td></tr></tbody></table></div><h2 id="quick-reference">Quick reference</h2><h6>Flags</h6><div class="table-wrapper"><table><thead><tr><th>Flag</th><th>Effect</th></tr></thead><tbody><tr><td><code>-fdec</code></td><td>Master switch. Turns on every extension above; off, each one is a compile error. Implies OSVS <code>PERFORM</code> range, the word/longword/quadword storage model, native byte order, and RMS file I/O, each individually overridable.</td></tr><tr><td><code>-fdec-constants=<file></code></td><td>Loads additional <code>VALUE IS EXTERNAL</code> constants. Checked before the built-in table. Repeatable.</td></tr><tr><td><code>-fno-perform-osvs</code></td><td>Turns off the OSVS <code>PERFORM</code> range implied by <code>-fdec</code>.</td></tr><tr><td><code>-fbinary-size=</code> / <code>-fbinary-byteorder=</code></td><td>Overrides the storage model implied by <code>-fdec</code>.</td></tr><tr><td><code>-fcallfh=EXTFH</code></td><td>Uses the compiler's own file layer instead of VX/RMS.</td></tr><tr><td><code>-Wno-dec-hint</code></td><td>Silences the default warnings for accepted-and-ignored RMS tuning clauses.</td></tr></tbody></table></div><h6>Interop cheat sheet</h6><div class="kw-grid"><div>CALL "R" USING BY DESCRIPTOR X RETURNING S</div><div>01 S PIC S9(9) COMP VALUE EXTERNAL SS$_NORMAL.</div><div>01 P USAGE POINTER VALUE REFERENCE ITEM.</div><div>SET S TO SUCCESS</div><div>IF S IS FAILURE</div><div>PROCEDURE DIVISION GIVING RET-STAT.</div><div>SET P TO REFERENCE OF ITEM.</div><div>PROGRAM-ID. NAME WITH IDENT "V1.0".</div></div><h6>File I/O cheat sheet</h6><div class="kw-grid"><div>VALUE OF ID IS "x"</div><div>APPLY LOCK-HOLDING ON f</div><div>OPEN ... ALLOWING ALL</div><div>READ ... REGARDLESS [OF LOCK]</div><div>READ ... PRIOR</div><div>READ/REWRITE ... ALLOWING NO OTHERS/UPDATERS</div><div>UNLOCK f ALL RECORDS</div></div><h6>Getting started</h6>
<pre><span class="cmt"># Compile a VSI-style program</span>
cobc -fdec -fformat=terminal prog.cob
<span class="cmt"># Supply application-specific constants</span>
cobc -fdec -fdec-constants=msgcodes.h prog.cob</pre>
</div>