BankLang

Target conformance

The rules the generated artifacts obey, each with the manual it comes from.

This is the page that turns "we think it compiles" into something checkable. Every rule below is enforced by one of two passes that read a .cbl, .cpy or .jcl as text and know nothing about how it was produced — that independence is the point. A checker written from the same belief as the emitter agrees with the emitter, including where the emitter is wrong.

The two passes ask different questions, and the second exists because for two years nothing was asking it:

Both read the same three sets of artifacts, collected once in tools/generated-artifacts.ts so that neither lane can pass by reading less than the other:

Manuals, as extracted in vendor-docs/:


COBOL

Rule Limit Source
line-length A source line ends at column 72. LR, "Reference format"
sequence-area Columns 1–6 are the sequence number area; this compiler numbers nothing. LR, "Reference format"
indicator-area Column 7 holds a blank, -, *, / or D. LR, "Reference format"
area-a Area A holds a division, section or paragraph header, an FD/SD entry, or a level 01 or 77 indicator. Nothing else. LR, "Area A"
word-length A COBOL word is at most 30 characters. LR, "COBOL words"
program-id-length The program-name becomes a load module member name, which is at most eight. LR, "PROGRAM-ID paragraph"
literal-length An alphanumeric literal is at most 160 characters. LR, "Alphanumeric literals"
picture-length A PICTURE character-string is at most 50 characters. LR, "PICTURE clause"
digit-count An arithmetic operand has at most 18 digits under ARITH(COMPAT). PG, "ARITH"
reserved-word A reserved word is not a data name or a paragraph name. LR, Appendix E
vocabulary Every word is a name the artifact declares or a word Enterprise COBOL reserves. LR, Appendix E
call-resolvable Every CALL "X" names a program the run unit will hold. PG, "Resolving external references"
duplicate-name Two things in one program are not declared under the same name, compared under the path that qualifies them. LR, "User-defined words"
literal-delimiter Every alphanumeric literal in one artifact is delimited the same way. Style rather than conformance; see below. LR, "Alphanumeric literals"
process-statement A CBL or PROCESS statement begins in column 1 and precedes every source line. LR, "PROCESS (CBL) statement"
unreferenced-item A generated work field is referenced by the program that declares it. PG, "Data division"
uninitialised-storage A generated work field in WORKING-STORAGE carries a VALUE. An item without one is unpredictable. LR, "VALUE clause"
pic-alignment Every PIC clause in a group of siblings starts in one column. PG, "Data division"

The delimiter rule, which is not a conformance rule

Enterprise COBOL takes either delimiter, so nothing here is refused by the target. It is in the linter because it is refused by a reviewer, and because the 2026-08-05 audit's F13 came back: MOVE 'Y' two lines under a VALUE "N" survived in a shipped example, its evidence bundle and a golden fixture, while a test asserting exactly this passed. The test's program reached the boolean written as a condition, which emits IF … MOVE "Y" … ELSE MOVE "N", and never the boolean written as a literal, which emits the MOVE alone.

The rule reads the artifact rather than the emitter: whichever delimiter more of its literals use is the one it has chosen, and a literal written with the other one is reported. A literal whose text contains the chosen delimiter is exempt, because switching is one of the two ways COBOL allows that character to appear. That exemption is what lets the generated zUnit driver hold AZU2001W THE TEST " in apostrophes, which is the shape IBM's own generator produces. EXEC blocks are skipped: an SQL string constant is delimited by an apostrophe and a delimited identifier by a quote, and those are SQL's rules.

The vocabulary rule

This is the one that matters most, and the one that would have caught the 2026-08-05 audit's first finding.

ROUNDED MODE IS NEAREST-EVEN was emitted for two years. It compiled under GnuCOBOL's default dialect, which is a superset of every COBOL it knows, and it reads like COBOL. NEAREST-EVEN appears in no column of the Language Reference's Appendix E — not reserved, not an unimplemented 85 Standard word, not a word that might be reserved in a future release. Enterprise COBOL has never heard of it.

A checker that asks whether the compiler in front of it accepted the text cannot tell that. One that asks whether the target has ever heard of the word can.

The word list is not typed here. tools/extract-ibm-words.ts pulls it out of Appendix E's own table, taking the leftmost of the three columns — the words "reserved for function implemented in Enterprise COBOL" — plus Table 59's intrinsic function names. pnpm words:extract regenerates it, and the diff is the review.


JCL

Rule Limit Source
card-length A statement's fields end at column 71. JCL, "Format of statements"
name-field A name field is one to eight characters. JCL, "Name field"
dsn-qualifier Each qualifier is one to eight characters and does not begin with a digit. JCL, "DSNAME parameter"
dsn-length A qualified dataset name is at most 44 characters. JCL, "DSNAME parameter"
continuation A card ending in a comma is followed by //, a blank in column 3, and the field resuming in columns 4 through 16. JCL, "Continuing statements"
required-dd A step has the DDs it cannot run without. PG, "Compile and link-edit procedure (IGYWCL)"

What required-dd knows


z/OS semantics

The rules above are all about whether the toolchain will accept the text. This section is about what happens when it does.

packages/zos-lint exists because the 2026-08-07 audit found two shipped programs that could not do what they claimed on the target, and every check in this repository passed on both. The conformance linter read their style, cobc read their syntax, the differential runtime read their arithmetic, and the examples verified. None of those asks "this program aborts on connect" or "this reply is discarded", because none of them is a question about behaviour.

Rule Behaviour Source
mq-connection-per-manager Two MQCONN calls naming one queue manager do not keep two handles. MQ, "MQCONN", usage note 3
mq-already-connected The test after an MQCONN forgives MQRC_ALREADY_CONNECTED. MQ, "MQCONN", usage note 3
cics-commarea-answered The record returned through DFHCOMMAREA is one the program writes into. CICS, "Passing data to other programs by using COMMAREA"

What each one caught

mq-connection-per-manager. examples/mq-request-reply declares two queues on CSQ1, and the emitter paired a connect with every open. IBM's MQCONN usage note 3 says the second call to a queue manager you are already connected to returns "the same [handle] as that returned by the previous MQCONN call" — so two handles to one manager are one handle under two names, and the first MQDISC ends both.

mq-already-connected. The same usage note says that second call comes back with MQCC_WARNING and MQRC_ALREADY_CONNECTED, and "Use the connection handle returned in this situation as normal." The generated test read NOT = MQCC-OK and abended the step with RC 12 — before it read a message, on a connection that was working.

cics-commarea-answered. A CICS program is passed a pointer to the caller's communication area, and it is the only thing the caller gets back. examples/online-enquiry computed a balance into a second record and moved the record it had been given back into DFHCOMMAREA: the enquiry answered with the question. BANK-CICS-005 refuses that shape in the source; this is the same rule read off the artifact, which is what catches it arriving by some other route.

What this pass deliberately does not report

A generated CICS transaction jumps to its exit paragraph when a called paragraph sets the failure code, which skips the write-back. That path ends in EXEC CICS ABEND, where the task is ending and the caller reads nothing: reporting it would be reporting the abend path for not filling in an answer nobody receives.

The pass is meant to grow. A rule arrives here when something is found that runs, and is wrong.


What conformance does not mean

It means the text obeys the rules the manuals state. It does not mean the program has been compiled by IBM Enterprise COBOL, and nothing in this repository has been. Local compilation is GnuCOBOL under tools/banklang-ibm.conf, which is shaped to the target rather than being it.

divergences.md is the list of places the two are known or suspected to disagree. zos/README.md is the kit for someone with a machine.


Read this page as Markdown on GitHub →