STRUMENTA LANGUAGE ENGINES · COBOL

All 459 programs of the NIST COBOL-85 suite, and the copybooks you actually have.

The public conformance suite is the bar we publish, because you can download it and count it yourself. What earns the license is the machinery underneath: area-aware lexing, recursive copybook expansion with pseudo-text replacement, and a position on every node that still points at the original source line afterwards.

Most COBOL front ends parse the tutorial and fail on the estate. The difference is almost never the grammar. It is the seven columns before the code starts, and the copybook that arrives with a different prefix each time it is included.

The engine at a glance
CORECOBOL-85
CONFORMANCE459 NIST CCVS85 programs
FORMATSFIXED_FORMAT · HP_TANDEM_FORMAT
PREPROCESSINGCOPY · COPY REPLACING · REPLACE
OUTPUTAST · JSON · XML · LionWeb
RUNTIMEJVM library · CLI

A number you can check yourself

NIST CCVS85 · newcob.val · published by the US National Institute of Standards and Technology

Most parser pages ask you to believe a percentage. This one points at a public, vendor-neutral conformance suite that anybody can download, and tells you the shape of what is in it. The suite is part of our regression corpus.

The NIST COBOL-85 validation suite, as it sits in the repository

nist-testsuite/

# the suite is distributed as one file
nist-testsuite/newcob.val

# uncompressed, it is:
459  .cob      COBOL-85 programs
 52  .coblib   copy-library members
511  files total

# the CCVS85 families it covers
NC  nucleus            SQ  sequential I/O
IC  inter-program call  RL  relative I/O
IF  conditionals        IX  indexed I/O
ST  sort-merge          RW  report writer
SM  source manipulation CM  communication
DB  debug               SG  segmentation
OB  obsolete features   EX  copy library
Two marked lines you can verify without us. Download newcob.val from NIST, run the uncompressor, and count the .cob files. The suite is more than 345,000 lines of COBOL, and it is joined in the regression run by 12 open-source COBOL codebases and 681 automated tests. The honest caveat, stated here rather than in a footnote: CCVS85 tests the COBOL-85 standard. It does not test IBM Enterprise COBOL extensions, it does not test CICS, and it does not test Db2.

Everything difficult happens before the parser runs

area predicates · separate token channels · clean-text to original mapping

A COBOL line is not a line of code. It is six columns of sequence number, one indicator column, an Area A, an Area B and eight columns the compiler ignores — and what a character means depends on which of those it lands in. A period in column 7 is not a period.

The COBOL fixed-format reference record, and what each column region means Columns 1 to 6 are the sequence number area. Column 7 is the indicator area, carrying an asterisk or slash for a comment, a hyphen for a continuation, a D for a debugging line or a dollar sign for a directive. Columns 8 to 11 are Area A, which holds division, section and paragraph headers and level 01 and 77 entries. Columns 12 to 72 are Area B. Columns 73 to 80 are the identification area, ignored by the compiler. 1–6 sequence 7 ind 8–11 Area A 12–72 Area B 73–80 ignored EACH REGION GOES TO ITS OWN TOKEN CHANNEL. THE LEXER ASKS WHICH REGION IT IS IN BEFORE IT DECIDES WHAT A CHARACTER IS. line identifiers * / comment   – continuation   D debugging   $ directive divisions, sections, paragraphs, 01 and 77 statements, clauses, everything else identification AND AFTER CONTINUATION LINES ARE JOINED AND COPYBOOKS EXPANDED, EVERY COLUMN STILL MAPS BACK TO AN ORIGINAL LINE AND COLUMN.

The lexer is area-aware in the strict sense: the rules for the period, the parentheses, the string literal and the end-of-line comment are guarded by predicates that ask which area the lexer is currently in. Line identifiers, the indicator column, whitespace and comments each go to their own token channel, so they are available to a tool that wants them and invisible to a grammar that does not.

Then there is the preprocessor, which is where COBOL front ends really die. COPY member REPLACING ==:PFX:== BY ==CUST== is pseudo-text substitution at inclusion time, including partial-word replacement — so the same copybook included twice with different prefixes produces two different record layouts. A copybook is not a compilation unit either: it can be a fragment of a data description, a fragment of the Procedure Division, or an unbalanced fragment of neither.

Copybooks are expanded at the token level through a resolver you supply, because only you know your SYSLIB concatenation or your library list. REPLACE, REPLACE LEADING, REPLACE TRAILING and REPLACE OFF are grammar rules. EXEC SQL INCLUDE is a second, independent include mechanism with its own resolver.

And underneath all of it, a mapping from every column of the joined, area-stripped “clean” text back to an original line and column. That is what lets a diagnostic point at the real source line after a literal has been continued across two records and a copybook has been expanded three levels deep. It is the single most useful thing this engine does and it is invisible until you need it.

Input — fixed-format COBOL, with the ruler

CUSTRPT.cob, plus copybook CUSTREC

----+----1----+----2----+----3----+----4---
       IDENTIFICATION DIVISION.
       PROGRAM-ID. CUSTRPT.
       ENVIRONMENT DIVISION.
       CONFIGURATION SECTION.
       SPECIAL-NAMES.
           DECIMAL-POINT IS COMMA.
       DATA DIVISION.
       FILE SECTION.
       FD  CUST-FILE.
       01  CUST-REC.
           COPY CUSTREC REPLACING ==:PFX:== BY ==CUST==.
       WORKING-STORAGE SECTION.
       01  WS-STATUS        PIC XX VALUE SPACES.
           88  WS-EOF                 VALUE '10'.
       01  WS-TOTAL   PIC S9(9)V99 COMP-3 VALUE ZERO.
       01  WS-EDITED        PIC ---.---.--9,99.
       PROCEDURE DIVISION.
       MAIN-PARA.
           OPEN INPUT CUST-FILE
           PERFORM UNTIL WS-EOF
               READ CUST-FILE
                   AT END SET WS-EOF TO TRUE
                   NOT AT END
                       ADD CUST-BALANCE TO WS-TOTAL
               END-READ
           END-PERFORM
           STOP RUN.
The copybook CUSTREC contains 05 :PFX:-ID PIC X(8). and two siblings. It is a fragment, not a program, and it only becomes a record layout after :PFX: becomes CUST. Note also that DECIMAL-POINT IS COMMA has already changed what , and . mean by the time the editing picture on the marked line is read.

Output — parse tree, by grammar rule

intermediate rules elided

compilationUnit
└── program CUSTRPT
    ├── ⋯ environment division
    │   └── decimalPointIsComma = true
    ├── ⋯ data division
    │   ├── dataDescriptionEntry 01 CUST-REC, line 11
    │   │   ├── dataDescriptionEntry 05 CUST-ID, CUSTREC line 1
    │   │   ├── dataDescriptionEntry 05 CUST-NAME, CUSTREC line 2
    │   │   └── dataDescriptionEntry 05 CUST-BALANCE, CUSTREC line 3
    │   └── dataDescriptionEntry 88 WS-EOF, line 15
    └── ⋯ procedure division
These are real rule names in the shipped grammar. The three fields inside CUST-REC did not exist in the program file: they came from the copybook, arrived with CUST substituted for :PFX:, and still carry a position that points at the copybook line they came from. That provenance is what makes an impact analysis defensible.

Four constructs that decide the project

Not the hardest to parse — the hardest to model. Each of these is a place where treating COBOL as a normal programming language produces an answer that is quietly wrong.

A record is a byte layout, not a struct

REDEFINES gives the same bytes a second, incompatible interpretation. OCCURS DEPENDING ON makes the layout dynamic, so the offset of a field depends on a value at run time. Level 66 RENAMES regroups across boundaries. A data migration that treats an 01 as a struct of fields is already wrong on line one.

       01  TXN-REC.
           05  TXN-COUNT   PIC S9(4) COMP.
           05  TXN-LINE OCCURS 1 TO 99 TIMES
                   DEPENDING ON TXN-COUNT.
               10  TXN-AMT PIC S9(7)V99 COMP-3.
           05  TXN-RAW REDEFINES TXN-LINE PIC X(900).

PICTURE is a language of its own

An editing picture is an output format, a sign convention and a storage decision at once. COMP-3 is packed decimal; S9(7)V99 has an implied decimal point that exists nowhere in the bytes. Modeled as structure rather than stored as a string, because a migration has to reproduce the arithmetic, not the spelling.

       01  WS-EDITED   PIC ---.---.--9,99.
       01  WS-PACKED   PIC S9(7)V99 COMP-3.
       01  WS-BLANK    PIC 9(4) BLANK WHEN ZERO.

Control flow is labels, not blocks

PERFORM A THRU Z executes every paragraph between two labels in source order, including the ones nobody meant to include. Paragraphs fall through. ALTER rewrites the target of a GO TO at run time. Building a correct control-flow graph from COBOL is materially harder than from a block-structured language, and it is the analysis that tells you which third of a 200,000-line program can be deleted.

           PERFORM VALIDATE-PARA THRU VALIDATE-EXIT
           ALTER SWITCH-PARA TO PROCEED TO NIGHT-PARA
           GO TO SWITCH-PARA.

Two embedded languages, captured verbatim

EXEC SQL and EXEC CICS are first-class statements in the grammar. The SQL is captured as a block with its position, in the Data Division as well as the Procedure Division. CICS commands are recognized with their options tokenized. Neither is parsed here — the SQL is a job for a SQL engine, and that is a feature rather than an omission. See the band below.

           EXEC SQL
               SELECT BALANCE INTO :CUST-BALANCE
               FROM   CUSTOMER WHERE ID = :CUST-ID
           END-EXEC
           EXEC CICS SEND MAP('CUSTM') ERASE END-EXEC

Both of those EXEC examples are IBM Enterprise COBOL on z/OS — the mainframe. IBM i is a midrange platform and has no CICS at all. We keep the two apart on purpose, because merging them is how a re-platforming estimate ends up wrong by a quarter.

Coverage, by construct

Core is COBOL-85. Dialect extensions are scoped deliberately: we would rather name what we cover and extend it for you than claim a universe.
Construct How it is handled Status
COBOL-85 standard the whole NIST CCVS85 suite in the regression run Supported — the stated core
Fixed format, 80-column reference record FIXED_FORMAT, area predicates, indicator column Supported
HP Tandem format HP_TANDEM_FORMAT Supported
COPY, and COPY … REPLACING with pseudo-text token-level expansion through a resolver you supply Supported
REPLACE, REPLACE LEADING, REPLACE TRAILING, REPLACE OFF replaceStatement Supported
Continuation lines, including inside a literal joined, with a reverse map to the original line and column Supported
DECIMAL-POINT IS COMMA a parser setting, because it changes lexing Supported
Nested programs and copybook fragments compilationUnit, program, endProgram Supported — a unit may start at any division
ACU COBOL extensions dialect work outside the core Selected extensions supported
Micro Focus RM COBOL and Visual COBOL dialect work outside the core Partial — tell us your compiler and we will be specific
EXEC SQL and EXEC CICS blocks execSqlStatement, execCicsStatement, execSqlInclude Recognized and positioned; contents preserved verbatim
Cross-file symbol resolution Not part of this engine — and we will not pretend otherwise
Free-format COBOL Not supported — the engine reads fixed and HP Tandem
COBOL 2002 / 2014 / 2023 features object orientation, national data, >> directives Not claimed
AN INTEGRATION STEP, NAMED IN ADVANCE

You supply the search order. We supply everything downstream of it.

The default copybook resolver does nothing, on purpose. Only you know your SYSLIB concatenation, your library list, and which of the four copies of CUSTREC on your system is the one this program compiled against.

This is the part most COBOL parser pages do not mention, and it is the part that costs a week if you discover it late. There are two pluggable resolvers: one for COPY, one for EXEC SQL INCLUDE. You implement the lookup; the engine does the token splicing, applies the pseudo-text replacements, and keeps the position mapping intact through every level of expansion.

Naming it is more useful than a page that promises the integration will be effortless and leaves you to discover otherwise. It is a small, well-defined interface, it takes an afternoon, and it is the only place your environment has to meet the engine. Everything after it — the tree, the positions, the diagnostics, the serialization — is ours.

And in practice you will not have all the copybooks. Customers send forty thousand programs and thirty thousand of thirty-five thousand copybooks. Error tolerance is not a nicety here: malformed or unresolvable input returns a partial tree plus positioned issues, so a batch finishes and tells you exactly what it could not find.

The interface you implement

two resolvers, nothing else

// your copybook search order
interface CopyResolver {
  fun resolveCopyImport(
    importName: String,
    replacements: List<Replacement>
  ): List<Token>
}

// EXEC SQL INCLUDE is separate
interface ExecSqlResolver {
  fun resolveSqlInclude(
    importName: String
  ): List<Token>
}
Expansion happens at the token level, recursively, with the replacements applied — which is why the same copybook included under two prefixes yields two correct record layouts rather than one wrong one.
459
NIST CCVS85 PROGRAMS IN THE REGRESSION CORPUS
52
COPY-LIBRARY MEMBERS ALONGSIDE THEM
681
AUTOMATED TESTS
12
OPEN-SOURCE COBOL CODEBASES ALSO IN THE RUN
THE REST OF THE PROGRAM

The SQL in a COBOL program is not a separate project.

“Which paragraph writes to which table, through which host variable” is one question. Answering it with two unrelated parsers means writing the join yourself, twice, and then maintaining it.

This engine isolates and positions the EXEC SQL block. A Strumenta SQL engine parses what is inside it. Both produce nodes in the same model — so one traversal crosses the boundary, and a host variable in the SQL and its 01 declaration in Working-Storage are two nodes in one tree rather than two strings in two reports.

Every Strumenta engine is built on Starlasu, so a COBOL tree, a SQL tree and an RPG tree have the same shape, the same traversal model and the same API. That is what you cannot assemble by gluing unrelated open-source parsers together: separate models, separate idioms and separate sets of edge cases to reconcile before you have written a line of analysis.

Every engine also supports LionWeb, so the models interchange with LionWeb-compliant tooling instead of being locked inside one process — and every engine is available through bindings from Java, Kotlin, Python, TypeScript and C#. The host application picks the language; the parser does not.

Engines in the same estate

one model, one traversal

SQL engine →
What is inside the EXEC SQL block.

PL/SQL engine →
The packages the batch calls, if the database is Oracle.

RPG & DDS engine →
For estates that run z/OS and IBM i side by side.

The whole catalog →
15+ engines, one AST framework underneath.

What you receive

A library, a command-line tool, the documents that explain the tree, and a person to write to. No mainframe or IBM i connection is required: you analyze exported sources offline.

01 The engine

A JVM library and a command-line tool

Kotlin on the JVM, on Kolasu — the JVM implementation of Starlasu. Use it as a library from Java or Kotlin, or run the command-line tool over a directory and collect serialized trees.

library · CLI · JVM
02 The model

A designed AST, positioned through the preprocessor

Not a renamed parse tree: parse-tree-to-AST mapping is a separate layer, so the model is deliberate. Every node and every issue carries a position on the original source file, after continuation joining and copybook expansion. Serialize to JSON or XML; interchange through LionWeb.

JSON · XML · LionWeb · positions preserved
03 The integration

Two resolvers, and a printer

You implement the copybook and EXEC SQL INCLUDE lookups for your environment; we do everything downstream. A printer that renders the AST back to COBOL text is also part of the product — useful for refactoring pipelines, and worth testing on your own sources before you build a plan around round-tripping.

CopyResolver · ExecSqlResolver · printer
04 The license

Standard, Distribution or Service — support included

Standard for use inside your own organization, Distribution if the engine ships inside a product you sell, Service if it runs behind a service you operate. A license file is registered once per process and refreshed from our license service, on the same terms as every other engine in the catalog. Support is part of the license, and we also do training, architectural design, implementation and coaching around it.

three tiers · support included
Onboarding

Week one is writing forty lines of copybook resolver and then running the engine over your own programs.

There is nothing to install on the mainframe and nothing to provision. Before any of that, paste a program into the Strumenta Playground — pick COBOL — and watch a real AST come back from the same engine. If the integration needs help, that is what the support in the license is for; if it needs more than help, we do that work too. Write to products@strumenta.com.

Why license this rather than start from the open-source COBOL parsers

COBOL is the one language on this catalog where the open-source options are genuinely good, and we are not going to build a straw man. ProLeap, by Ulrich Wolffgang and contributors, is MIT-licensed, ANTLR4-based, has a real preprocessor that executes COPY and REPLACE, extracts EXEC SQL and EXEC CICS as text, and passes the NIST suite. The antlr/grammars-v4 COBOL-85 grammar is there too. If you are writing a one-off analysis over clean COBOL-85 and you enjoy this kind of work, start there and we will not be offended.

Here is where the calculation changes. Dialects are where COBOL projects die, and dialect work is not grammar work — it is a long tail of vendor extensions found one customer at a time. Our core is COBOL-85, with selected ACU COBOL extensions and partial Micro Focus RM COBOL and Visual COBOL support, and the offer we actually make is to tell you what we cover for your compiler and extend it where we do not. An open-source project cannot make that offer, because nobody is accountable for it.

Second, the estate is not only COBOL. The value of this engine is disproportionately that its tree is the same shape as the SQL tree, the PL/SQL tree and the RPG tree, so one tool answers questions that cross the boundary. Two unrelated open-source parsers give you two models and a join you write and maintain yourself.

Third, interchange. LionWeb export and bindings from Java, Kotlin, Python, TypeScript and C# mean the model leaves the JVM. If the tool consuming your COBOL model is written in Python or C#, that is not a serialization exercise you have to design.

Fourth, someone to call. That sounds like a brochure line until the week you have a program that will not parse, a deadline, and an issue tracker whose last reply was in 2021. Support is included in the license, and the people answering are the people who wrote the lexer predicates.

The method behind our estimates has a name: read the Chisel Method for how we make parser work estimable, or Migration Services if what you actually need is the migration rather than the engine.

What to discuss before you license

Six things we would rather tell you now than have you find in week three.

  • Free-format COBOL is not supported. The engine reads the fixed 80-column reference record and HP Tandem format. If your sources are free format, this is a scoping conversation before it is a purchase.
  • Copybook resolution is your responsibility. The default resolver is a no-op. Without one, COPY statements are recognized but not expanded, and your Data Division is a stub. It is a small interface, but it is an integration task and it belongs in your plan.
  • Embedded SQL and CICS are captured, not parsed. You get the block, its options and its exact position. Analyzing what the SQL does needs a SQL engine, which is a licensing question rather than a technical obstacle. CICS command options are tokenized, not modeled command by command.
  • There is no cross-file symbol resolution in this engine. The RPG, CL and EGL engines have semantics modules; COBOL does not. If your project needs a resolved, whole-codebase model rather than a per-program tree, say so early — it is work that can be scoped, not a switch we can flip.
  • Dialect coverage is scoped, not universal. COBOL-85 is the core. Selected ACU COBOL extensions and partial Micro Focus RM COBOL and Visual COBOL are supported. Everything else — Enterprise COBOL extensions, Fujitsu, Unisys, GnuCOBOL — is a conversation, and a productive one, but not a checkbox on this page.
  • It runs on a JVM. If your toolchain is Python, TypeScript or C#, you use the bindings or the serialized tree rather than the jar in-process — which works, and is worth designing for deliberately rather than discovering late.

What we will ask you

  1. Which dialect and compiler, and which version?
  2. Fixed format or free format — and are the sequence-number and identification areas populated?
  3. Can you supply all the copybooks, and the search order? Roughly how many COPY … REPLACING sites are there?
  4. Is there EXEC CICS? EXEC SQL? EXEC DLI? Do you need those parsed, or isolated and inventoried?
  5. DECIMAL-POINT IS COMMA, a non-default CURRENCY SIGN, a non-standard ALPHABET?
  6. Any ALTER, PERFORM … THRU, or nested programs? These decide whether control-flow analysis is a week or a quarter.
  7. How many programs, how many copybooks, how many lines, and in what encoding?
  8. Target: documentation and analysis, data-layout extraction for a file migration, an editor, or transpilation?

Straight answers

What exactly does “459 NIST programs” mean?

The NIST COBOL-85 validation suite, CCVS85, is distributed as a single file called newcob.val. Uncompressed it is 459 .cob programs and 52 .coblib copy-library members, covering the nucleus, sequential, relative and indexed I/O, inter-program communication, sort-merge, report writer, segmentation, debug and the obsolete-features families. The whole suite is in our regression corpus. It tests the COBOL-85 standard — not IBM extensions, not CICS, not Db2.

Do you expand our copybooks?

The engine does the expansion; you supply the lookup. Copybooks are spliced in at the token level, recursively, with COPY … REPLACING pseudo-text substitutions applied, including partial-word replacement — and every resulting node still carries a position that maps back to the original file and line. What the engine cannot know is your SYSLIB concatenation or your library list, so you implement a small resolver interface for that.

Which dialects does it support?

COBOL-85 is the core, and it is the standard the commercial dialects build on. Beyond it we support selected ACU COBOL extensions and partial Micro Focus RM COBOL and Visual COBOL. We do not claim universal dialect coverage, because nobody honestly can. Tell us your compiler and we will tell you what we cover for your code, and what it would take to cover the rest.

Does it read free-format COBOL?

No. The supported source formats are the fixed 80-column ANSI reference record and HP Tandem format. Free format arrived with COBOL 2002 and we do not support it today. If your estate is free format, tell us before anything else, because it changes the answer to every other question.

Can we use it from Python, TypeScript or C#?

Yes. The engine is built on Starlasu and is available through bindings from Java, Kotlin, Python, TypeScript and C#, and it supports LionWeb, so the model interchanges with LionWeb-compliant tooling. If you would rather not embed anything, the command-line tool serializes the tree to JSON or XML and any language can read that.

Name your compiler it is the only question that changes everything

Tell us which COBOL you actually run.

Enterprise COBOL on z/OS, ILE COBOL on IBM i, Micro Focus, ACU, RM, Fujitsu, Unisys, GnuCOBOL — with the version. Send that, with a handful of representative programs and the copybooks they use, and we will come back with what parses today, what would need dialect work, and how much.

Scroll to Top