MODULE 7 · WORKING WITH TEXT · 2/8

Reference modification

12 min30 XPExercise

Often you need part of a field: the year of a date, the last four digits of a card number, the first letter of a name. Reference modification lets you address any substring of a data item without declaring a subfield for it:

identifier(start:length)

start is the 1-based position of the first byte, length is how many bytes. Leave out the length to mean "to the end of the field".

       IDENTIFICATION DIVISION.
       PROGRAM-ID. REFMOD.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-DATE      PIC X(8)  VALUE "20260924".
       01  WS-NAME      PIC X(12) VALUE "HOPPER".
       PROCEDURE DIVISION.
           DISPLAY WS-DATE(1:4) "-" WS-DATE(5:2) "-" WS-DATE(7:)
           DISPLAY "INITIAL: " WS-NAME(1:1)
           STOP RUN.

Output:

2026-09-24
INITIAL: H

Variables as positions

Both start and length can be numeric data items or arithmetic expressions, which makes reference modification the way to walk through a field one character at a time:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. SPELL.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-WORD      PIC X(5)  VALUE "COBOL".
       01  WS-I         PIC 9(2).
       PROCEDURE DIVISION.
           PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 5
               DISPLAY WS-I ": " WS-WORD(WS-I:1)
           END-PERFORM
           STOP RUN.

This prints 01: C, 02: O, and so on. WS-WORD(WS-I + 1:2) works too.

As a receiving field

A reference-modified item can be the target of a MOVE. Only the addressed bytes change; the rest of the field is untouched:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. MASK.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-ACCT      PIC X(10) VALUE "4400123987".
       PROCEDURE DIVISION.
           MOVE ALL "*" TO WS-ACCT(1:6)
           DISPLAY WS-ACCT
           STOP RUN.

Output: ******3987. MOVE ALL "*" fills the whole receiving area (here six bytes) with asterisks.

Things to watch

  • The result of reference modification is always alphanumeric, even if the field is numeric. WS-AMOUNT(1:3) gives you three digit characters, not a number.
  • Positions are not checked by default. WS-DATE(7:5) on an 8-byte field reads past the end into whatever is next in storage. On the mainframe, compile with SSRANGE during testing to catch this.
  • Positions count bytes. On the mainframe, text is EBCDIC, one byte per character, so this is rarely a surprise.

On the job

Old programs often define a date field with a REDEFINES and three subfields just to get at the year. Reference modification does the same job inline, and you will see both styles side by side in legacy code. Neither is wrong; follow the style of the program you are changing.

Your task

A card statement program needs two formatted values. Read two lines from input:

  1. A transaction date as YYYYMMDD, e.g. 20260924
  2. A 16-digit card number, e.g. 4929123456783456

Display the date in day/month/year order and the card number with all but the last four digits masked:

DATE: 24/09/2026
CARD: ************3456

Use reference modification to pick the pieces out and to mask the card number. Do not declare subfields or use REDEFINES.

fixed format
Run your program to see its output here. The first visible test's input and datasets are used.
Submit to grade your program against every test.