PROCs, Symbols and Overrides

COBOL COBOL 2014 (ISO/IEC 1989:2014), built with GnuCOBOL 3.x · ✓ verified by execution on 2026-08-16

In the real world of mainframe execution, job control scripts can get massive. Imagine having a fifty-line script that compiles, binds, and executes a program, and you need to run it for twenty different datasets. Writing out a thousand lines of JCL would be an unmaintainable nightmare.

To solve this, JCL uses Procedures (PROCs). A PROC is a pre-written, reusable segment of JCL that can be invoked repeatedly from different calling jobs using a simple EXEC statement. You can think of a PROC as a function or method in a standard programming language, but for job control.

Calling Job (MYJOB.JCL) //MYJOB JOB ... //STEP1 EXEC PROC=MYPROC // PARM='VALUE' Procedure (MYPROC.PROC) //MYPROC PROC //PSTEP1 EXEC PGM=COBPROG //INFILE DD DSN=&DSNAME

Symbolic Parameters

When you call a PROC, you often need to change a few details—like what dataset it reads from. JCL accomplishes this through symbolic parameters. A symbolic parameter is a placeholder name preceded by an ampersand (&).

Here is the whole mechanism in two short members. This is real JCL as it would be catalogued on z/OS; it cannot run here, because nothing off the mainframe reads it.

//* ---- the PROC, catalogued once and reused ----
//MYPROC   PROC INFILE='TEST.DATA.SET'
//PSTEP1   EXEC PGM=COBPROG
//STEPLIB  DD DSN=PROD.LOADLIB,DISP=SHR
//INFILE   DD DSN=&INFILE,DISP=SHR
//SYSOUT   DD SYSOUT=*
//         PEND
//*
//* ---- a job that calls it, overriding the symbol ----
//MYJOB    JOB (ACCT01),'NIGHTLY',CLASS=A
//STEP1    EXEC PROC=MYPROC,INFILE='PROD.DATA.SET'

The PROC line declares the symbol and gives it a defaultTEST.DATA.SET. That default is the safety net: run the PROC with no override and it reads test data, not production. The calling job supplies INFILE='PROD.DATA.SET', which replaces &INFILE everywhere it appears before the step runs.

This is where the classic production incident comes from. Misspell the symbol on the EXEC line — INFIL= instead of INFILE= — and JCL does not stop. The override simply never matches, the default stands, and the nightly job quietly reads the test dataset. Nothing errors, the return code is zero, and the numbers are wrong. The habit that saves you is making the default obviously non-production, exactly as above, so a failed override looks wrong immediately instead of plausibly.

Running locally with GnuCOBOL there is no JCL, but the same shape exists: pass the value as an environment variable and read it with ACCEPT ... FROM ENVIRONMENT.

cobol ✓ verified output
       IDENTIFICATION DIVISION.
       PROGRAM-ID. SYMBOL-DEMO.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 INFILE-PARM PIC X(20).
       PROCEDURE DIVISION.
           ACCEPT INFILE-PARM FROM ENVIRONMENT "MY_PARM".
           IF INFILE-PARM = SPACES
               DISPLAY "No parameter passed!"
           ELSE
               DISPLAY "Processing dataset: " INFILE-PARM
           END-IF.
           STOP RUN.
Output
No parameter passed!

DD Overrides

Sometimes, a PROC is 99% perfect, but you need to change one specific file definition for a single run without altering the reusable PROC itself. You can achieve this using a DD override.

By supplying a DD statement in your calling job that matches the stepname.ddname of the PROC, the mainframe will substitute your custom definition over the PROC’s default. Like symbolic parameters, this allows flexible execution of a single compiled program against many different data sources.

What happens if you use ACCEPT FROM ENVIRONMENT to simulate a numeric variable passing, and do arithmetic on it? Predict the output of this snippet. (Assume VAL is mapped to the string “05”).

Predict the output cobol

Read the code. What exactly will it print? Commit to an answer before you look.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. PREDICT-DEMO.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 INPUT-VAL PIC 99.
       01 RESULT    PIC 99.
       PROCEDURE DIVISION.
           ACCEPT INPUT-VAL FROM ENVIRONMENT "VAL".
           IF INPUT-VAL = 00 
               MOVE 05 TO INPUT-VAL
           END-IF.
           COMPUTE RESULT = INPUT-VAL * 3.
           DISPLAY RESULT.
           STOP RUN.
Output
15

Because VAL was unassigned in this snippet’s simulated environment, ACCEPT pulls in blanks or zeroes (depending on compiler). The IF block catches the 00 value and assigns 05. 05 * 3 gives 15. This demonstrates how programs can provide fallback defaults when symbolic parameters or overrides are omitted.

Check yourself

What is the primary purpose of a JCL PROC?

Reveal answer

To group reusable JCL statements so they can be invoked repeatedly. — A PROC (Procedure) is a pre-written segment of JCL that can be invoked repeatedly from different calling jobs using a simple EXEC statement, promoting reuse.

Which symbol is used to define a symbolic parameter in JCL?

Reveal answer

Ampersand (&) — Symbolic parameters in JCL use an ampersand (&) followed by the parameter name, like &DSNAME.

When applying a DD override, what determines which DD statement in the PROC is overridden?

Reveal answer

The stepname.ddname specified in the calling job. — A DD override is specified in the calling job by prefixing the DD name with the step name from the PROC, as in //stepname.ddname DD ...

Challenges

Challenge 1 +50 XP

Read the symbolic parameter 'ENV_DSN' from the environment.

cobol ✓ solution verified at build time

COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the fixed code should be, then open the solution and compare. The expected output below is real — it came from compiling the solution with GnuCOBOL when this page was built.

  • Test 1 — expects " "
Need a hint? (−25% XP)

Use ACCEPT ... FROM ENVIRONMENT to read the simulated parameter.

Show solution (0 XP)
       IDENTIFICATION DIVISION.
       PROGRAM-ID. CHALLENGE1.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 MY-DSN PIC X(20).
       PROCEDURE DIVISION.
           ACCEPT MY-DSN FROM ENVIRONMENT "ENV_DSN".
           DISPLAY MY-DSN.
           STOP RUN.

Challenge 2 +50 XP

Display OVERRIDDEN.

cobol ✓ solution verified at build time

COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the fixed code should be, then open the solution and compare. The expected output below is real — it came from compiling the solution with GnuCOBOL when this page was built.

  • Test 1 — expects "OVERRIDDEN"
Need a hint? (−25% XP)

Change the literal string being displayed.

Show solution (0 XP)
       IDENTIFICATION DIVISION.
       PROGRAM-ID. CHALLENGE2.
       PROCEDURE DIVISION.
           DISPLAY "OVERRIDDEN".
           STOP RUN.

🐞 Bug Hunt +25 XP

The PROC was supposed to override SYSOUTCLASS, but the override never arrived — so the program routes the report to a blank class instead of failing or defaulting. Make it detect the missing override and fall back to class A.

This code runs. It just does the wrong thing. Read it, find the defect, fix it — the tests below decide when you are right.

cobol ✓ solution verified at build time

COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the fixed code should be, then open the solution and compare. The expected output below is real — it came from compiling the solution with GnuCOBOL when this page was built.

  • Test 1 — expects "OVERRIDE NOT SUPPLIED - DEFAULTING\nROUTING REPORT TO CLASS: A\n"
Need a hint? (−25% XP)

An override that did not happen leaves the field exactly as you initialised it. Test for that before using the value.

Show solution (0 XP)
       IDENTIFICATION DIVISION.
       PROGRAM-ID. ProcOverride.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-SYSOUT-CLASS PIC X(1) VALUE SPACE.
       PROCEDURE DIVISION.
           ACCEPT WS-SYSOUT-CLASS FROM ENVIRONMENT "SYSOUTCLASS"
           IF WS-SYSOUT-CLASS = SPACE
               MOVE "A" TO WS-SYSOUT-CLASS
               DISPLAY "OVERRIDE NOT SUPPLIED - DEFAULTING"
           END-IF
           DISPLAY "ROUTING REPORT TO CLASS: " WS-SYSOUT-CLASS
           STOP RUN.