BankLang

COBOL Backend Specification

1. Target

Primary target:

ibm-enterprise-cobol-zos

Secondary local target:

gnucobol-local

The IBM target is the source of truth for generated enterprise COBOL style. The GnuCOBOL target exists for local testing and CI.

2. Reference format

Generated COBOL is written in fixed reference format, which is the only one Enterprise COBOL on z/OS reads. A source line is 72 characters: columns 1-6 are the sequence number area, column 7 is the indicator area, columns 8-11 are Area A and columns 12-72 are Area B. Columns 73-80 are the identification area and are not part of the program. SOURCEFORMAT(EXTEND) is an AIX option; there is nothing on z/OS that widens the line.

Nothing warns about crossing the margin. The compiler does not see the text past column 72, so a name is silently shortened and the compile fails somewhere else on a name the source appears to define. Every generated line therefore goes through packages/cobol-backend/src/reference-format.ts on its way out:

JCL follows its own version of the same rule: fields end at column 71, and a parameter field continues by breaking after a complete parameter including its comma, then resuming between columns 4 and 16 of a card beginning // and a blank.

Every cobc invocation in this repository passes -fixed. GnuCOBOL guesses the format from the first line and will read a whole program as free format, where none of these rules exist — which is a validation that proves nothing about the target. tests/reference-format.test.ts checks the margins and the areas over every generated artifact.

3. Generated COBOL style

The house style is a contract with a check against every rule, and it lives in generated-code-standards.md. The rules the target itself imposes, each with the manual it comes from, are in target-conformance.md. Neither is repeated here, because a second copy is a copy that goes stale — this section used to hold one, and it was still describing a PROGRAM-ID with a hyphen in it long after the compiler stopped emitting one.

4. Program structure

A generated program opens with the compiler options its behaviour depends on, then a prologue derived from the program itself:

CBL ARITH(COMPAT),TRUNC(STD),NUMPROC(NOPFD),NOSSRANGE
CBL RENT,NODYNAM,QUOTE,PGMNAME(COMPAT)
      *> ---------------------------------------------------------------
      *> ACCOUNTT — AccountTransfer
      *>
      *> Generated by bankc from main.bank.ts.
      *> ...
      *> ---------------------------------------------------------------
       IDENTIFICATION DIVISION.
       PROGRAM-ID. ACCOUNTT.

       DATA DIVISION.
       WORKING-STORAGE SECTION.

       PROCEDURE DIVISION.
       BANK-MAIN.

The PROGRAM-ID is at most eight characters and carries no hyphen, because under the default PGMNAME(COMPAT) an external program-name is folded to uppercase, truncated to eight and has its hyphens translated to zero — so PROGRAM-ID. ACCOUNT-TRANSFER. would define the entry point ACCOUNT0 while the job's EXEC PGM= said something else. The program-name, the load module member, the artifact file name and the EXEC PGM= are one string from one rule.

BANK-MAIN is the only paragraph that ends the program. Every routine has an exit paragraph and every caller performs it THRU that paragraph, so a failure leaves through one path rather than ending where it was found.

Which sections appear depends on what the program uses: an ENVIRONMENT DIVISION and FILE SECTION only where there are files, a LINKAGE SECTION only where something is passed in, a REPORT SECTION only where a report is declared.

5. Data mapping

Decimal

decimal<18, 2>;

Default IBM COBOL mapping:

PIC S9(16)V99 COMP-3

The exact mapping must be controlled by backend profile and documented.

String

string<16>;

COBOL:

PIC X(16)

Bool

PIC X(1) VALUE "N"

One character, "Y" or "N", initialised false. No condition names are generated for it: a bool is tested by comparing the field, and an 88 would be a second spelling of the same two values. Enums are the opposite case — they carry one 88 per member, because there the member name is what the procedure division should be naming.

Date

PIC 9(8)

Format:

YYYYMMDD

6. Copybook generation

Generated copybooks must:

7. Paragraph generation

Function:

function validateAmount(amount: decimal<18, 2>): bool;

Generated paragraph name:

VALIDATE-AMOUNT.

Rules:

8. Decimal operations

Decimal operations must preserve:

Generated COBOL must not silently truncate precision.

If a target COBOL operation may truncate, the compiler must emit either safe generated code or a compile-time diagnostic.

9. Db2 generation

Generated Db2 code must use:

EXEC SQL
  ...
END-EXEC.

Requirements:

10. CICS generation

Generated CICS code must use:

EXEC CICS
  ...
END-EXEC.

Requirements:

11. VSAM/file generation

Generated file programs must contain:

12. Source maps

Every emitted artifact must be traceable.

Source map fields:

{
  "sourceFile": "examples/account-transfer/src/main.bank.ts",
  "sourceStart": { "line": 10, "column": 1 },
  "sourceEnd": { "line": 18, "column": 2 },
  "artifact": "dist/cobol/ACCOUNTT.cbl",
  "targetStartLine": 120,
  "targetEndLine": 163,
  "category": "function",
  "symbol": "validateAmount"
}

13. Generated-code banner

Every generated source file should contain:

Generated by bankc.
Do not edit this file directly.
Source maps are available in dist/maps.

No timestamp in banner by default because output must be deterministic.

14. Unsupported target features

What the backend cannot emit fails with a diagnostic rather than with partial output. A program that compiles to something incomplete is worse than one that does not compile, because only the first reaches a reader who believes it.

Recursion is not on this list. It is emitted as a contained RECURSIVE program with LOCAL-STORAGE, and examples/amortisation-schedule runs it. status-and-limits.md is the current list of what is missing; this section is only about how a refusal behaves.


Read this page as Markdown on GitHub →