Das Minimum, das Sie vor dem Lesen von COBOL-Quellcode kennen sollten
· Go Komura · COBOL, Legacy-Technologie, Geschäftssysteme, Wartung, Mainframe
Übergaben, Störungsbehebung, die Wartung eines Fremdherstellerpakets. In solchen Situationen landet eines Tages plötzlich ein Berg COBOL-Quellcode auf dem Tisch.
- Die Dateinamen enden auf
.cbloder.cpy - Die Variablennamen stehen komplett in Großbuchstaben
- Reihen von
01,05,77,88 - Etwas wie
PIC S9(7)V99 COMP-3taucht auf – irgendwo zwischen Beschwörungsformel und Buchhaltungssoftware - Und dann ist da noch massenhaft
COPY, sodass die geöffnete Datei allein nicht einmal das große Ganze zeigt
An diesem Punkt bleiben die meisten Menschen erst einmal ratlos stehen.
Die Landkarte, die man zum Lesen braucht, ist aber gar nicht so groß. COBOL unterscheidet sich zwar von Compiler zu Compiler und von Produkt zu Produkt, doch das Grundgerüst, das man beim Lesen eines bestehenden Business-Systems zuerst greifen sollte, ist ziemlich einheitlich. Dieser Artikel ordnet, mit Blick auf IBM-typisches und allgemein übliches Business-COBOL, das Minimum für Menschen, die plötzlich COBOL-Quellcode lesen müssen.
1. Zuerst das Fazit (in einem Satz)
Ganz grob vorweg, aber praxistauglich formuliert, lautet es so:
- COBOL ist, bevor es eine Sprache der Logik ist, sehr stark eine Sprache der Datensatzdefinitionen
- Wer nur die
PROCEDURE DIVISIONliest, versteht höchstens die Hälfte. Zuerst dieDATA DIVISIONansehen PICist die Form eines Feldes,USAGEist die Darstellung, in der es gehalten wirdCOMP-3ist packed decimal. Es taucht ständig in der Welt der Beträge und Stückzahlen auf88ist keine eigene Variable, sondern ein condition-name, der dem Wert des vorangehenden Feldes einen Namen gibtREDEFINESist ein Mechanismus, um denselben Speicher in einer anderen Form zu betrachten. Es ist keine Kopie- Gibt es ein
COPY, ist die gerade geöffnete Quelle noch nicht vollständig. Ohne Blick in die Copybooks sieht man nicht das Ganze - Wer
PERFORM,IF,EVALUATE,READ,WRITEundCALLverfolgen kann, erfasst den größten Teil des Ablaufs - Alter Quellcode liegt im festen Format vor, in dem die Spaltenposition Bedeutung trägt. Die sichtbaren Leerzeichen sind keine bloße Verzierung1
Kurz gesagt: DIVISION, PIC, USAGE, COMP-3, REDEFINES, OCCURS, 88, COPY, PERFORM. Wer diese lesen kann, verirrt sich deutlich seltener.
2. COBOL zuerst als Sprache über die Form von Daten begreifen
Wer mit dem Instinkt von C# oder Java liest, will zuerst den ifs, for-Schleifen und Funktionsaufrufen folgen.
Bei COBOL ist es aber schneller, vorher zu klären: „Welche Datensätze empfängt dieses Programm, welche erzeugt es, und welche Puffer hält es?“
Typisches Business-COBOL läuft grob in diesem Ablauf:
- Datensätze aus einer Datei oder DB lesen
- Sie in
WORKING-STORAGE-Felder einlesen - Bedingt verzweigen
- Sie in einen anderen Datensatz umpacken
- Sie ausschreiben
Mit anderen Worten: Das Layout steht meist vor dem Algorithmus.
Hier ein typisches Grundgerüst als Beispiel.
IDENTIFICATION DIVISION.
PROGRAM-ID. SAMPLE01.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT SALES-FILE ASSIGN TO ...
DATA DIVISION.
FILE SECTION.
FD SALES-FILE.
01 SALES-REC.
05 SALE-ID PIC 9(8).
05 SALE-AMOUNT PIC S9(7)V99 COMP-3.
WORKING-STORAGE SECTION.
01 WS-EOF PIC X VALUE 'N'.
88 EOF VALUE 'Y'.
PROCEDURE DIVISION.
PERFORM UNTIL EOF
READ SALES-FILE
AT END
SET EOF TO TRUE
NOT AT END
PERFORM PROCESS-SALE
END-READ
END-PERFORM
STOP RUN.
Beim Lesen dieses Codes sollte man zuerst nicht auf PERFORM schauen, sondern auf den Typ von SALE-AMOUNT und die Bedeutung von EOF.
Liest man COBOL in dieser Reihenfolge, wird es plötzlich still.
3. Zuerst die vier DIVISIONs betrachten
COBOL-Quellcode gliedert sich zunächst grob in vier DIVISIONs.
| DIVISION | Was zuerst zu beachten ist |
|---|---|
IDENTIFICATION DIVISION |
Programmname, alte Kommentare, Herkunft |
ENVIRONMENT DIVISION |
Dateien, externe Ressourcen, Annahmen zur Ein-/Ausgabe |
DATA DIVISION |
Datensatzdefinitionen, Arbeitsbereiche, Parameter |
PROCEDURE DIVISION |
Der eigentliche Verarbeitungsablauf |
Besonders wichtig sind diese Bereiche.
FILE SECTIONEnthält die Datensatzdefinitionen für Ein-/AusgabedateienWORKING-STORAGE SECTIONEnthält alltägliche Variablen, Flags, Zähler, ArbeitspufferLOCAL-STORAGE SECTIONKann Bereiche enthalten, die bei jedem Aufruf neu initialisiert werdenLINKAGE SECTIONKann von außen übergebene Argumente enthalten – die Empfangsstelle eines Unterprogramms
Sieht man eine LINKAGE SECTION und PROCEDURE DIVISION USING ..., ist es sehr wahrscheinlich, dass das Programm nicht in sich abgeschlossen ist, sondern mit von außen übergebenen Daten arbeitet.
4. Vor dem Aussehen des festen Formats nicht erschrecken
In altem COBOL trägt die Spaltenposition selbst in einer Quellcodezeile Bedeutung. Wer das nicht weiß, wird nie herausfinden, „warum links dieser merkwürdige Rand ist“.1
Im festen Format gilt grob:
- Spalten 1–6: laufende Nummer
- Spalte 7: Indikator
- Spalten 8–11: Area A
- Spalten 12–72: Area B
Spalte 7 ist besonders wichtig.
*oder/: Kommentarzeile-: FortsetzungszeileD: debugging line*>: ein Kommentar, der auch mitten in der Zeile stehen kann
Den Zusammenhang zwischen Spalte und Inhalt sieht man mit einer Skala am besten. Die erste Zeile zeigt die Zehnerstelle, die zweite die Einerstelle der Skala.
1 2 3 4 5 6 7 8
12345678901234567890123456789012345678901234567890123456789012345678901234567890
SSSSSSIAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB........
S= laufende Nummer (Spalten 1–6)I= Indikator (Spalte 7)A= Area A (Spalten 8–11)B= Area B (Spalten 12–72).= ab Spalte 73. Wird je nach Compiler als Kennzeichnungsfeld genutzt, hat aber keinen Einfluss auf die Bedeutung des Programms
Auf echten Quellcode angewendet, sieht das so aus.
000100* Diese Zeile ist ein Kommentar, weil Spalte 7 ein * ist
000200 IDENTIFICATION DIVISION.
000300 PROGRAM-ID. SAMPLE01.
000400 DATA DIVISION.
000500 WORKING-STORAGE SECTION.
000600 01 WS-ORDER.
000700 05 WS-ORDER-ID PIC 9(8).
000800 05 WS-LONG-NAME PIC X(30) VALUE 'ABCDEFGHIJKLMNOPQRST
000900- 'UVWXYZ0123'.
Beim Lesen sind vier Punkte wichtig.
- Spalten 1–6 sind die laufende Nummer. Im Beispiel oben ist das die
000100-artige Nummerierung, und sie hat keinen Einfluss auf das Programmverhalten. Manchmal ist sie auch leer. - Spalte 7 ist der Indikator.
*bedeutet Kommentar,-bedeutet Fortsetzungszeile. Im Beispiel oben ist das die Zeile000900, die die Fortsetzung des Zeichenkettenliterals aus der vorherigen Zeile ist. - Spalten 8–11 sind Area A.
DIVISION,SECTION, Paragraphennamen,FDsowie die Stufennummern01und77beginnen hier. Im Beispiel oben beginnenIDENTIFICATION DIVISION.und01 WS-ORDER.in Area A. - Spalten 12–72 sind Area B. Gewöhnliche Anweisungen und untergeordnete Stufen wie
05werden hier geschrieben. Im Beispiel oben beginnt05 WS-ORDER-IDin Area B.
Die Leerzeichen hier sind keine „Formatierung“ im modernen Sinn, sondern teilweise Syntax. Eine Tab-Umwandlung im Editor, ein Linksbündig-Ausrichten oder ein achtloses Copy-Paste macht die Datei ohne Weiteres kaputt. Bei alten Quellen sollten Sie zuerst infrage stellen, ob die Datei fixed format oder free format ist. Wendet man auf fixed-format-Quellcode moderne Auto-Formatierung an, brechen die Grenzen zwischen Area A und Area B, und die Kompilierung schlägt fehl.
5. Das Minimum der DATA DIVISION
5.1 Stufennummern
COBOL-Datendefinitionen bilden ihre Hierarchie nicht über Einrückung, sondern über Stufennummern.2
01 WS-ORDER.
05 WS-ORDER-ID PIC 9(8).
05 WS-AMOUNT PIC S9(7)V99 COMP-3.
05 WS-STATUS PIC X.
88 WS-OK VALUE '0'.
88 WS-ERROR VALUE '9'.
77 WS-COUNT PIC 9(4).
Diese Mindestpunkte reichen völlig aus.
01: die zusammenhängende oberste Datensatzebene, eine Gruppe02–49: die darunterliegenden Ebenen77: ein eigenständiges Elementarfeld88: condition-name. Gibt dem Wert des vorangehenden Feldes einen Namen366: fürRENAMES. Kommt nicht häufig vor, existiert aber
Wichtig ist, 88 nicht als eigene bool-Variable zu betrachten.
Es gibt kein eigenes Feld namens WS-OK; vielmehr lässt sich WS-STATUS unter dem Namen WS-OK lesen, wenn es den Wert '0' hat – so ungefähr fühlt sich das an.
Ein weiterer wichtiger Punkt: Nicht die Leerzeichen, sondern die Stufennummern bestimmen die Hierarchie.
Die sichtbare Einrückung ist eine nützliche Orientierung, aber letztlich sollten Sie 01 / 05 / 10 / 88 vertrauen.2
5.2 PICTURE
PIC gibt die Form eines Feldes an.
Am häufigsten sieht man das hier.
| Notation | Grobe Bedeutung |
|---|---|
X |
Zeichen |
9 |
Ziffer |
S |
vorzeichenbehaftet |
V |
Dezimalpunkt existiert nur logisch |
X(10) |
10 Zeichen |
9(5) |
5-stellige Zahl |
S9(7)V99 |
vorzeichenbehaftet, 7 Ganzzahlstellen + 2 Nachkommastellen |
Zum Beispiel:
PIC X(10)→ 10 ZeichenPIC 9(5)V99→ 5 Ganzzahlstellen + 2 NachkommastellenPIC S9(7)V99→ vorzeichenbehaftet, 7 Ganzzahlstellen + 2 Nachkommastellen
Besonders wichtig ist hier V.
V besitzt kein tatsächliches .-Zeichen.
PIC 9(5)V99 wird als „Zahl mit 2 Nachkommastellen“ behandelt, aber in den Daten steht kein Punktzeichen.
Wer eine Datei oder einen Dump als „die sichtbare Zeichenkette“ interpretiert, stolpert daher fast immer.
5.3 USAGE / DISPLAY / COMP / COMP-3
Wenn PIC die Form ist, dann ist USAGE die Darstellung, in der das Feld gehalten wird.
Schon dieses Minimum reicht, um sehr viel lesen zu können.45
| Notation | Grobe Bedeutung | Worauf beim Lesen zu achten ist |
|---|---|---|
DISPLAY |
externe Dezimalzahl, als Zeichen sichtbar | Auf dem Mainframe wird dabei manchmal EBCDIC vorausgesetzt6 |
COMP / BINARY |
binär | Die sichtbare Stellenzahl und die interne Darstellung sind zwei verschiedene Dinge |
COMP-3 / PACKED-DECIMAL |
packed decimal | Als Zeichen gelesen sieht es kaputt aus |
Zum Beispiel:
01 WS-AMOUNT-DISP PIC S9(7)V99.
01 WS-AMOUNT-BIN PIC S9(7) COMP.
01 WS-AMOUNT-PACK PIC S9(7)V99 COMP-3.
Alle drei sind „Zahlen“, aber sie halten ihren Inhalt unterschiedlich.
In der Praxis zahlt sich am meisten der Reflex aus, den man beim Anblick von COMP-3 entwickelt.
- Das ist packed decimal
- Vermutlich ein Betrag, ein Steuerbetrag, eine Stückzahl oder ein Satz
- Als Text betrachtet sieht es zwangsläufig kaputt aus
- Wer es im CSV- oder UTF-8-Modus betrachtet, erlebt einen Unfall
Diese Grundhaltung sorgt dafür, dass man beim Anblick von Dumps und Binärdateien nicht unnötig in Panik gerät.
Wie COMP-3 tatsächlich als Bytefolge aussieht
Das hier lohnt sich, einmal von Hand nachzuvollziehen – danach ändert sich der Blick darauf dauerhaft.
Die Regeln von packed decimal sind nur zwei.45
- In ein Byte werden 2 Dezimalziffern gepackt
- Nur das letzte Byte ganz rechts enthält die niederwertigste Ziffer und das Vorzeichen
Das Vorzeichen wird als 4-Bit-Wert dargestellt, wobei C für positiv, D für negativ und F für vorzeichenlos steht.
Zur Überprüfung dient ein Beispiel aus dem IBM-Handbuch.4
| Definition | Wert | Bytefolge |
|---|---|---|
PIC S9(4) PACKED-DECIMAL |
+1234 |
01 23 4C |
PIC S9(4) PACKED-DECIMAL |
-1234 |
01 23 4D |
PIC 9(4) PACKED-DECIMAL |
1234 |
01 23 4F |
1234 hat 4 Stellen, weshalb durch Regel 2 vorn eine freie halbe Stelle entsteht. Das ist die führende 0.
Nach demselben Prinzip lässt sich das in diesem Artikel schon mehrfach erwähnte PIC S9(7)V99 COMP-3 nachvollziehen.
S9(7)V99bedeutet 7 Ganzzahlstellen + 2 Nachkommastellen = 9 StellenVgibt nur die Position des Dezimalpunkts an, verbraucht also kein einziges Byte- Packt man 9 Stellen zu je 2 Stellen pro Byte, ergeben sich 4 Bytes, für die restliche Stelle und das Vorzeichen 1 weiteres Byte. Insgesamt 5 Bytes
Bei einem Wert von +12345.67 ergibt sich, auf 9 Stellen aufgefüllt, 001234567, also:
Wert : +12345.67
9-stellig : 0 0 1 2 3 4 5 6 7 und Vorzeichen
Bytefolge : 00 12 34 56 7C
^ Vorzeichen C = positiv
Bei einem negativen Wert -12345.67 ändert sich nur das letzte Byte zu 7D.
Bytefolge : 00 12 34 56 7D
Die eigentliche Frage lautet: Wie sieht das aus, wenn man es als Text öffnet? Bildet man 00 12 34 56 7C gewaltsam Byte für Byte auf ASCII ab, ergibt sich:
00ist NUL,12ist ein Steuerzeichen – beide lassen sich gar nicht als Zeichen darstellen34ist4,56istV,7Cist|
Auf dem Bildschirm erscheint also so etwas wie „einige nicht darstellbare Zeichen, gefolgt von 4V|“. Die Folge 12345.67 taucht nirgendwo auf.
Das ist das eigentliche Wesen von „sieht aus wie Mojibake, ist aber nicht kaputt“. Stoßen Sie beim Öffnen eines Dumps auf eine unverständliche Bytefolge, sollten Sie zuerst vermuten, ob die USAGE dieses Feldes vielleicht COMP-3 ist.
Als Ergänzung noch eine Faustregel, um von der Stellenzahl auf die Byteanzahl zu kommen. Die Byteanzahl ergibt sich aus „die Anzahl der 9en durch 2 teilen, den Nachkommaanteil abrunden und 1 addieren“.
| Anzahl der 9en in der PICTURE | Byteanzahl bei COMP-3 |
|---|---|
| 1 | 1 |
| 2–3 | 2 |
| 4–5 | 3 |
| 6–7 | 4 |
| 8–9 | 5 |
| 10–11 | 6 |
| 12–13 | 7 |
Dass bei derselben Byteanzahl jeweils zwei Stellenzahlen nebeneinanderstehen, liegt daran, dass nur bei einer geraden Anzahl von 9en vorn eine freie halbe Stelle entsteht. Deshalb wird S9(4) zu den 3 Bytes 01 23 4C, und auch S9(5) kommt mit denselben 3 Bytes aus.
Beim Abgleich des Layouts mit einer externen Datei verschiebt sich ohne diese Tabelle alles um jeweils ein Byte.
Noch eine kleine Ergänzung: DISPLAY bedeutet nicht zwangsläufig eine ASCII-Zeichenkette.
Auf z/OS-Systemen wird EBCDIC vorausgesetzt, deshalb kann selbst wenn Ziffern wie Zeichen aussehen, der Bytewert von ASCII '0'–'9' abweichen.6
5.4 REDEFINES / OCCURS / COPY / FILLER
Diese vier sind beim Lesen die typischen Stolperstellen.
REDEFINES
REDEFINES ist ein Mechanismus, um denselben Bereich in einer anderen Form zu betrachten. Es ist keine Kopie.7
01 REC-BUF.
05 REC-TYPE PIC X.
05 REC-DATA PIC X(99).
01 HEADER-REC REDEFINES REC-BUF.
05 HDR-TYPE PIC X.
05 HDR-DATE PIC 9(8).
05 FILLER PIC X(91).
Das kommt dem Gefühl einer union aus der C-Familie nahe.
Es taucht oft in der Form auf: „Ein und dieselben 100 Bytes werden je nach Datensatztyp unterschiedlich gelesen.“
OCCURS
OCCURS ist ein Array. In COBOL nennt man das gern table.
05 WS-ITEM OCCURS 12 TIMES.
10 WS-PRICE PIC 9(5).
Taucht zusätzlich OCCURS DEPENDING ON auf, handelt es sich um eine variable Tabelle.
In diesem Fall kann sich das auch auf die Position nachfolgender Felder auswirken, sodass man mit einer Denkweise für feste Längen leicht den Boden unter den Füßen verliert.8
COPY
COPY ist ein Include zur Compile-Zeit.
Das heißt, die gerade geöffnete Quelle ist möglicherweise noch nicht die vollständige Form.9
COPY CUSTOMER-REC.
COPY ERROR-MAP.
Es ist ziemlich üblich, dass Datensatzdefinitionen, gemeinsame Flags, Host-Variablen für SQL und externe Schnittstellen in Copybooks stecken.
Ist der Code wegen vieler COPY schwer lesbar, ist es schneller zu prüfen, ob man an die expandierte Quelle oder ein Compiler-Listing herankommt. IBM Enterprise COBOL bietet dafür auch MDECK, eine Option, mit der die Eingabequelle nach der Bibliotheksverarbeitung ausgegeben wird.10
FILLER
FILLER ist ein namenloses Feld.
Das heißt aber nicht „ungenutzt, also bedeutungslos“.
- reservierter Bereich
- eine Kompatibilitätslücke für eine alte Spezifikation
- Auffüllung zum Angleichen der Datensatzlänge
- Freiraum für
REDEFINES
All das kommt ganz normal vor.
FILLER hat nur keinen Namen – als Byteanzahl existiert es trotzdem.
Vergisst man das, verschiebt sich der Abgleich mit einer externen Datei Byte für Byte.
6. Das Minimum der PROCEDURE DIVISION
Ist die DATA DIVISION die Landkarte, ist die PROCEDURE DIVISION die Route, die man zurücklegt.
6.1 PERFORM
PERFORM ist die grundlegende Steuerübergabe in COBOL.
Grob gesagt bedeutet es: eine Verarbeitung aufrufen und zurückkehren.11
Am häufigsten sieht man diese Form.
PERFORM INIT-PROC
PERFORM UNTIL EOF
PERFORM READ-PROC
IF NOT EOF
PERFORM EDIT-PROC
PERFORM WRITE-PROC
END-IF
END-PERFORM
Bei PERFORM gibt es im Wesentlichen zwei Varianten.
- out-of-line
PERFORM, das einen Paragraphen oder eine Section benennt - inline
PERFORM ... END-PERFORM, das den Block direkt an Ort und Stelle schreibt
In älterem Code begegnet einem außerdem regelmäßig die Bereichsangabe PERFORM A-100 THRU A-199.
Das ist praktisch, aber wird nachträglich ein Paragraph in der Mitte eingefügt, gerät er leicht ungewollt mit in den Bereich. Beim Lesen sollte man deshalb genau hinschauen, wo der Bereich endet.
6.2 IF / EVALUATE / Scope
Für bedingte Verzweigungen ist IF das Grundwerkzeug.
EVALUATE als eine Art switch/case zu betrachten, trifft es größtenteils.
Worauf man achten muss, ist wie ein Scope endet.12
Code mit expliziten Terminatoren wie
END-IFEND-PERFORMEND-READ
lässt sich noch gut lesen.
Das Problem ist alter Code. In COBOL wirkt der . als impliziter scope terminator und schließt auf einen Schlag alle noch offenen Anweisungen.12
Das bedeutet, ein einziger Punkt entscheidet:
- wie weit ein
IFreicht - wie weit ein
PERFORMreicht - wo das nächste sentence beginnt
Außerdem ist NEXT SENTENCE nicht dasselbe wie CONTINUE.
NEXT SENTENCE springt hinter den nächsten Punkt, weshalb sich das Sprungziel je nach Position des folgenden . verschiebt.12
Beim Lesen von altem COBOL fährt man gut damit, nicht auf das Zeilenende, sondern auf den Punkt zu achten.
6.3 READ / WRITE / CALL
In Business-COBOL kommen vor allem diese vor.
READWRITEREWRITESTARTCALL
Besonders READ ... AT END ... ist der Klassiker.
READ IN-FILE
AT END
SET EOF TO TRUE
NOT AT END
PERFORM PROCESS-REC
END-READ
Gibt es ein CALL 'SUBPGM' USING ..., springt die Ausführung in ein anderes Programm.
In dem Fall lohnt sich ein Blick in die LINKAGE SECTION und die PROCEDURE DIVISION USING der Gegenseite – die Form der Übergabe wird dadurch weitgehend sichtbar.
7. Was außerhalb von COBOL liegt
COBOL ist häufig eine Welt, die sich nicht allein im Quellcode erschöpft.
- Dateidefinitionen
- die Ausführungsumgebung
- DB-Verbindungen
- der Transaktionskontext
- Job-Steuerung
liegen außerhalb.
Zumindest diese Punkte machen das Lesen deutlich leichter.
Dateien und FILE STATUS
Die FILE-CONTROL der ENVIRONMENT DIVISION und die FILE SECTION / FD der DATA DIVISION liest man als Paar.13
SELECT IN-FILE ASSIGN TO ...
FILE STATUS IS WS-FS.
FD IN-FILE.
01 IN-REC.
05 ...
Gibt es ein FILE STATUS, erhält es nach jeder E/A den Ergebniscode.
Beim Lesen von dateibezogenen Störungen oder der EOF-Erkennung kommt man ohne diesen Blick nicht weiter.14
EXEC SQL
Taucht das auf, handelt es sich um eingebettetes SQL.
EXEC SQL
SELECT ...
END-EXEC.
In diesem Fall ist COBOL nur „das Gefäß für Host-Variablen“, während die eigentlichen Auswahlbedingungen und Aktualisierungsziele auf der SQL-Seite liegen.
Der schnellste Weg ist daher, den Inhalt von EXEC SQL wie gewöhnliches SQL zu lesen.
EXEC CICS
Taucht das auf, befindet man sich im CICS-Transaktionskontext.15
EXEC CICS
RECEIVE MAP(...)
END-EXEC.
Ab diesem Moment ist es kein reines Batch-Lesen mehr. Man muss es zusammen mit dem externen Kontext lesen: Bildschirmmasken, Transaktionen, Antwortcodes, COMMAREA und Ähnliches.
JCL und Ausführungsdefinitionen
Im Mainframe-Batch ist es nicht ungewöhnlich, dass welches Dataset tatsächlich zugewiesen wird und in welcher Reihenfolge Jobs ablaufen, außerhalb des COBOL-Quellcodes liegt. Sieht man nur den Quellcode und findet nicht heraus, „wo diese Datei liegt“, liegt das oft nicht am Code, sondern schlicht daran, dass der betrachtete Ausschnitt noch nicht groß genug ist.
Unterschiede zwischen Compilern
Dieser Artikel ist mit Blick auf IBM-Systeme geschrieben, aber in der Praxis begegnet man auch Micro Focus oder COBOL unter Linux/Windows. Das Grundgerüst ist gemeinsam, deshalb ändert sich die Lesart nicht, aber die Stellen, an denen „dieselbe Schreibweise, aber ein anderes Ergebnis“ auftritt, sind bekannt – wer sie vorher kennt, vermeidet Fehler.
| Worauf zu achten ist | z/OS-Systeme (IBM Enterprise COBOL) | Open-Systeme (Micro Focus, Linux-/Windows-Version usw.) |
|---|---|---|
| Zeichenkodierung | EBCDIC wird vorausgesetzt6 | ASCII wird vorausgesetzt6 |
| Referenzformat | fixed format ist traditionell der Standard. free format ist ebenfalls wählbar1 | verfügt über beides, fixed und free, und welches Standard ist, hängt von der Build-Konfiguration ab1 |
| Suche nach Copybooks | Bibliotheksangabe | Suchpfadangabe über Compiler-Optionen |
| Dialekt | – | Es gibt eine Option, um umzuschalten, an welchem Compiler man sich orientiert |
Besonders wirksam ist die Zeichenkodierung. Selbst bei identischem PIC X(10) erhält man, wenn eine unter z/OS geschriebene Datei unverändert unter Windows gelesen wird, sogar bei Ziffern abweichende Bytewerte. Ein Großteil von „nach der Übertragung war alles kaputt“ liegt genau hieran – ein anderes Problem als bei COMP-3.
Auch bei der internen Darstellung von Zahlen gibt es eine Stelle, an der sich Unterschiede häufig zeigen. Bei IBM Enterprise COBOL werden BINARY / COMP-4 auf die in der PICTURE angegebene Stellenzahl abgeschnitten, während COMP-5 den Wert bis zur nativen Kapazität einer 2-, 4- oder 8-Byte-Binärzahl behält, und auch das Abschneiden erfolgt entsprechend der Binärgröße.16 Das heißt, PIC S9(4) COMP und PIC S9(4) COMP-5 sehen zwar gleich aus, unterscheiden sich aber in der Obergrenze der zulässigen Werte. Taucht COMP-5 in Code auf, der binäre Werte unverändert mit anderen Systemen austauscht, sollten Sie davon ausgehen, dass es absichtlich so geschrieben wurde.
Der kürzeste Ablauf, um dies mit der eigenen Umgebung abzugleichen, sieht so aus.
- Zuerst die Build-Definition öffnen (Makefile, JCL, Projekteinstellungen). So erfährt man, mit welchem Compiler und welchen Optionen kompiliert wird, noch bevor man den Quellcode selbst liest.
- Das Referenzformat (fixed / free) festlegen. Irrt man sich hier und formatiert dann im Editor, geht die Datei kaputt.
- Die Zeichenkodierung festlegen. Ob EBCDIC oder ASCII, ändert die Art, wie man einen Dump liest.
- Felder vom Typ
COMPmarkieren. Genau hier zeigen sich fast alle Unterschiede zwischen Compilern.
8. Die sichere Lesereihenfolge
Muss man plötzlich COBOL lesen, ist folgende Reihenfolge sicher.
- Alle
COPYdurchgehen Copybooks öffnen, wenn möglich. Wenn nicht, nach Listing oder expandierter Quelle suchen - Die Datensatzdefinitionen der
01-Ebene erfassen Die obersten Ebenen vonFILE SECTION,WORKING-STORAGEundLINKAGE SECTIONauflisten PICundUSAGElesen Beträge, Datumsangaben, Stückzahlen, Codes, Flags identifizieren- Nach
READ/WRITE/REWRITE/CALL/EXEC SQL/EXEC CICSsuchen Zuerst Ein-/Ausgabe und externe Grenzen erfassen - Nur dem ersten Hauptpfad folgen
Der PERFORM-Kette vom Anfang der
PROCEDURE DIVISIONan nachgehen 88und Status-Felder betrachten Die Bedeutung von EOF, Erfolg/Fehler und Typcodes wird dadurch leichter lesbarREDEFINES/OCCURS DEPENDING ON/COMP-3markieren Sie wirken sich später garantiert aus, deshalb vorab als Gefahrenstellen kennzeichnen- Bei Dateien den
FILE STATUSbetrachten Das verringert Fehllesungen bei E/A-Fehlern erheblich
Bei dieser Reihenfolge muss man nicht sofort den gesamten Text im Detail lesen. Bei COBOL ist es deutlich entspannter, nicht von Anfang an 100 % verstehen zu wollen, sondern zuerst die drei Punkte Datensätze, externe Grenzen, Hauptpfad zu fassen und erst danach in die Details zu gehen.
8.1 Übung: Diese Datensatzdefinition lesen
Nur die Erklärung der Lesart festigt sich nicht von selbst, deshalb hier eine kleine Datensatzdefinition zum Üben. Finden Sie erst selbst die Antworten, bevor Sie unten nachsehen.
01 CUST-REC.
05 CUST-ID PIC X(8).
05 CUST-NAME PIC X(20).
05 CUST-KBN PIC X.
88 CUST-NORMAL VALUE '0'.
88 CUST-VIP VALUE '1'.
05 CUST-BALANCE PIC S9(7)V99 COMP-3.
05 CUST-HIST OCCURS 3 TIMES.
10 HIST-DATE PIC 9(8).
10 HIST-AMOUNT PIC S9(5)V99 COMP-3.
05 FILLER PIC X(4).
Aufgaben
- Wie viele Bytes umfasst
CUST-RECinsgesamt? - Ab welchem Byte, vom Anfang des Datensatzes gezählt, beginnt
CUST-BALANCE? - Ab welchem Byte beginnt das
HIST-AMOUNTdes 2. Eintrags? - Welcher condition-name wird wahr, wenn
CUST-KBNden Wert'1'enthält? - Öffnet man diese Datei in einem Texteditor, welches Feld sieht kaputt aus?
- Nennen Sie 2 Dinge, die sich allein aus dieser Definition nicht erschließen.
Antworten
-
74 Bytes. Die Aufschlüsselung sieht so aus.
Feld Berechnung Byteanzahl CUST-IDX(8)8 CUST-NAMEX(20)20 CUST-KBNX1 CUST-BALANCECOMP-3 mit 9 Stellen 5 CUST-HIST(8 + 4)× 3-mal36 FILLERX(4)4 Summe 74 Die
88-Ebene ist ein condition-name, verbraucht also keine Bytes. Genau das mitzuzählen ist ein häufiger Fehler.FILLERhat nur keinen Namen – die 4 Bytes existieren durchaus. -
Ab Byte 30. Davor liegen
8 + 20 + 1 = 29Bytes, also beginnt es unmittelbar danach. -
Ab Byte 55.
CUST-HISTbeginnt bei Byte 35, ein Eintrag ist 12 Bytes lang, also liegt der 1. Eintrag bei Byte 35–46, der 2. bei Byte 47–58. Davon sind die ersten 8 BytesHIST-DATE, also beginntHIST-AMOUNTbei Byte 55. -
CUST-VIP. Es gibt kein eigenes Feld namensCUST-VIP; man kannCUST-KBNnur unter diesem Namen lesen, wenn es'1'enthält. -
CUST-BALANCEundHIST-AMOUNT. Beide sindCOMP-3, deshalb ergeben sie als Zeichen gelesen eine bedeutungslose Folge.HIST-DATEistPIC 9(8)mitDISPLAY, also in einer ASCII-Umgebung als Ziffern lesbar, etwa als20260317. In einer EBCDIC-Umgebung weichen die Bytewerte jedoch von ASCII ab, auch wenn es wie Ziffern aussieht. -
Zum Beispiel Folgendes.
- Ob diese Definition selbst über
COPYeingebunden ist. Ohne Blick in das Copybook lässt sich nicht sagen, ob es sich um die tatsächlich verwendete Version handelt. - Ob die Zeichenkodierung der Datei EBCDIC oder ASCII ist. Das ändert, wie
PIC XundPIC 9 DISPLAYaussehen. - Ob im Betrieb auch andere Werte als
'0'und'1'inCUST-KBNvorkommen. Es sind nur zwei condition-names definiert, das garantiert aber nicht, dass keine anderen Werte auftreten. - Die Eigenschaften der Datei selbst (Satzlänge, ob variabel lang,
FILE STATUS). Das lässt sich nur ausENVIRONMENT DIVISIONundFDerschließen.
- Ob diese Definition selbst über
Wer bei Aufgabe 1 oder 3 danebenlag, sollte zur Tabelle mit Stellenzahl und Byteanzahl in 5.3 zurückkehren. Lesefehler in COBOL beginnen meistens genau hier.
9. Häufige Stolperstellen
Zum Schluss eine Zusammenfassung der Stellen, an denen Einsteiger mit hoher Wahrscheinlichkeit hängen bleiben.
REDEFINES für „eine andere Variable“ halten
Falsch. Es ist derselbe Bereich, nur in anderer Form gelesen. Ändert man die eine Seite, ändert sich auch die Ansicht der anderen.7
88 für ein „eigenständiges bool“ halten
Falsch.
Es ist nur ein Name, der dem Wert des vorangehenden Feldes gegeben wird. SET WS-OK TO TRUE trägt im Hintergrund den entsprechenden Wert in das zugrunde liegende Feld ein.3
COPY ignorieren und nur den Haupttext lesen
Die geöffnete Datei ist noch nicht einmal die halbe Wahrheit. Dass Felddefinitionen, gemeinsame Flags und Host-Variablen komplett außerhalb liegen, ist normal.9
MOVE für eine einfache Zuweisung halten
MOVE ist kein bloßes memcpy.
Je nach Typ des Zielfeldes können Umwandlung, Stellenausrichtung, Nullauffüllung, Abschneiden sowie editing/de-editing dazukommen.17
Die Wirkung des . unterschätzen
Der . in COBOL ist schwerer, als man denkt.
In altem Code ohne explizite Terminatoren führt ein Fehleinschätzen von wie weit dieser Punkt schließt zu einer falschen Lesart des Kontrollflusses.12
packed decimal oder EBCDIC für „Mojibake“ halten
Nicht zwangsläufig kaputt. Sehr oft war es von Anfang an gar keine Zeichenkette oder einfach nicht ASCII.46
Annehmen, dass hinter OCCURS DEPENDING ON feste Positionen folgen
Bei einer variablen Tabelle können sich die Positionen der nachfolgenden Felder je nach Wert verschieben. Wer mit einer Denkweise für feste Längen liest, verschiebt alle Offset-Berechnungen.8
10. Schnellreferenz: Was zuerst zu bedenken ist
| Gefundenes Wort | Was zuerst zu bedenken ist |
|---|---|
01 |
Oberste Ebene eines Datensatzes oder einer Gruppe. Von hier aus das Gesamtbild erfassen |
88 |
Name für eine Bedeutung eines Flags oder Statuscodes. Der Schlüssel zum Lesen von Verzweigungen |
PIC X(...) |
Zeichenfeld |
PIC 9(...) / S9(...)V... |
numerisches Feld. Stellenzahl und Dezimalposition prüfen |
COMP |
binär |
COMP-3 |
packed decimal. Wahrscheinlich ein Betrag oder eine Stückzahl |
REDEFINES |
derselbe Bereich, anders interpretiert |
OCCURS |
Array/table |
OCCURS DEPENDING ON |
variable Länge. Auch auf nachfolgende Positionen achten |
FILLER |
kein Name, aber vorhandene Länge |
COPY |
ohne Copybook sieht man nicht die vollständige Form |
PERFORM |
das Grundgerüst des Hauptpfads |
READ / WRITE / REWRITE |
Datei-E/A |
EXEC SQL |
DB-Verarbeitung |
EXEC CICS |
Transaktionsverarbeitung |
FILE STATUS |
E/A-Ergebniscode |
11. Zusammenfassung
COBOL ist nicht deshalb schwierig, weil es alt ist. Es ist nur so, dass Datendefinitionen, externe Dateien und der Ausführungskontext eng miteinander verflochten sind, wodurch der erste Zugang schwer zu erkennen ist.
Das Minimum zum Lesen noch einmal zusammengefasst:
- Mit den
DIVISIONs die Landkarte erfassen - Zuerst die
DATA DIVISIONlesen - Mit
PICundUSAGEdie Form der Felder lesen COMP-3,REDEFINES,OCCURS,88,COPYmarkierenPERFORM,READ,WRITE,CALLverfolgen- Mit
FILE STATUS,EXEC SQL,EXEC CICSdie externen Grenzen erfassen - Die Wirkung des
.nicht auf die leichte Schulter nehmen
Ist das einmal sichtbar, wird COBOL von „geheimnisvoller uralter Magie“ zu „einer Sprache für Datensatzverarbeitung“. Legacy-Technologie ist nicht deshalb beängstigend, weil der Name alt klingt – es ist nur so, dass ein falsch gewählter erster Maßstab die Sache plötzlich unverständlich macht. Stimmt der Maßstab der Landkarte, liest sie sich erstaunlich normal.
12. Quellen
Die wichtigsten im Text verwendeten Referenzen. Die hochgestellten Nummern im Text verlinken direkt auf diese Liste, und über den Pfeil am Ende jedes Eintrags gelangen Sie zur ursprünglichen Stelle zurück.
-
IBM, „Reference format“ / IBM, „Area A or Area B“ / Micro Focus, „Fixed Format“ ↩ ↩2 ↩3 ↩4
-
IBM, „Level-numbers“ ↩ ↩2
-
IBM, „Format 2: condition-name value“ ↩ ↩2
-
IBM, „Examples: numeric data and internal representation“ ↩ ↩2 ↩3 ↩4
-
IBM, „PACKED-DECIMAL (COMP-3)“ ↩ ↩2
-
IBM, „The EBCDIC character set“ / IBM, „Handling differences in ASCII SBCS and EBCDIC SBCS characters“ ↩ ↩2 ↩3 ↩4 ↩5
-
IBM, „REDEFINES clause“ ↩ ↩2
-
IBM, „OCCURS DEPENDING ON clause“ ↩ ↩2
-
IBM, „COPY statement“ ↩ ↩2
-
IBM, „PERFORM statement“ / IBM, „Procedure division structure“ ↩
-
IBM, „Scope terminators“ / IBM, „Coding a choice of actions“ ↩ ↩2 ↩3 ↩4
-
IBM, „FILE STATUS clause“ / IBM, „Using file status keys“ ↩
-
IBM, „Computational items“ ↩
-
IBM, „Elementary move rules“ ↩
Verwandte Artikel
Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.
Eine Legacy-Business-Anwendung ohne Tests sicher verändern ── Charakterisierungstests und Refactoring in der Praxis
Um eine Business-Anwendung ohne Tests sicher zu verändern, erklärt dieser Artikel anhand von C#-Beispielen das Vorgehen bei einem Charakt...
Wenn Sie ein System ohne Quellcode und ohne Dokumentation übernehmen — Ein praktisches Playbook, um es am Laufen zu halten
Ein praktisches Playbook für den Beginn von Betrieb und Wartung eines Geschäftssystems ohne Quellcode und ohne Spezifikationen. Behandelt...
Wie lange lässt sich MSMQ noch nutzen? ── Die Migrationsentscheidung für eine Legacy-Queue, die nicht einmal „deprecated“ ist
MSMQ steht nicht auf Microsofts offiziellen Deprecated-Listen, doch System.Messaging existiert nur im .NET Framework und blockiert die Mi...
Verwenden Sie den ausgelesenen Wert eines QR-Codes nie ungeprüft — Erfolgreiche Fehlerkorrektur garantiert nicht den Wert
Die Fehlerkorrektur von QR-Codes ist kein Mechanismus, der garantiert, dass der Wert korrekt ist, sobald die Korrektur gelingt. Anhand vo...
Mit REST-APIs aus PowerShell arbeiten — Invoke-RestMethod in der Praxis
Ein praktischer Leitfaden zum Aufruf interner und SaaS-REST-APIs aus PowerShell: das Übergeben von Authentifizierungsheadern, das Vermeid...
Verwandte Themen
Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.
Technische Windows-Themen
Portal zu Windows-Entwicklung, Fehleranalyse und der Nutzung bestehender Assets.
Leistungen zu diesem Thema
Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.
Technische Beratung und Design-Review
Wie man vorhandene COBOL-Bestände liest, wo eine Änderung ansetzt, das Erfassen externer Grenzen und die Einordnung vor einer Migration – all das passt gut zu technischer Beratung und Design-Reviews.
Fehleruntersuchung und Ursachenanalyse
Störungsbehebung direkt nach einer Übergabe oder die Suche danach, wo in COBOL-Beständen Inkonsistenzen entstehen, lässt sich gut als Fehleruntersuchung und Ursachenanalyse angehen.
Häufige Fragen
Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.
- Wo sollte man beim Lesen von COBOL-Quellcode anfangen?
- Wenn Sie nur die PROCEDURE DIVISION lesen, verstehen Sie höchstens die Hälfte. COBOL ist, bevor es eine Sprache der Logik ist, sehr stark eine Sprache der Datensatzdefinitionen – deshalb sehen Sie sich zuerst die DATA DIVISION an. Der sichere Leseablauf lautet: alle COPY-Anweisungen durchgehen und die Copybooks prüfen, die Datensatzdefinitionen der 01-Ebene auflisten, die Form der Felder anhand von PIC und USAGE lesen, mit READ, WRITE, CALL, EXEC SQL und EXEC CICS suchen, um Ein-/Ausgabe und externe Grenzen zu erfassen, und erst danach der PERFORM-Kette am Anfang der PROCEDURE DIVISION folgen, um nur den Hauptpfad zu verfolgen.
- Was bedeutet PIC S9(7)V99 COMP-3?
- PIC gibt die Form eines Feldes an, USAGE gibt an, in welcher Darstellung es gespeichert wird. S9(7)V99 ist eine vorzeichenbehaftete Zahl mit 7 Ganzzahlstellen und 2 Nachkommastellen, aber V ist nur ein logisches Dezimaltrennzeichen – in den Daten steht kein tatsächliches Punktzeichen. COMP-3 ist packed decimal und taucht häufig bei Beträgen, Steuerbeträgen, Stückzahlen und Ratenfeldern auf. Als Text betrachtet sieht es zwangsläufig kaputt aus, deshalb geht es schief, wenn man einen Dump im CSV- oder UTF-8-Modus liest.
- Wie sollte man 88-Ebenen und REDEFINES in COBOL verstehen?
- 88 ist keine eigenständige bool-Variable, sondern ein condition-name, der einem Wert des vorangehenden Feldes einen Namen gibt. SET WS-OK TO TRUE trägt im Hintergrund den entsprechenden Wert in das zugrunde liegende Feld ein. REDEFINES ist ein Mechanismus, um denselben Speicherbereich in einer anderen Form zu betrachten – keine Kopie, sondern eher vergleichbar mit einer union aus der C-Familie. Ändert man die eine Seite, ändert sich auch die Ansicht der anderen, weshalb dieses Muster häufig verwendet wird, um innerhalb eines Bereichs verschiedene Datensatztypen zu unterscheiden.
- Was tun, wenn zu viele COPY-Anweisungen den Überblick verhindern?
- COPY ist ein Include zur Compile-Zeit, daher ist die gerade geöffnete Quelle möglicherweise noch nicht die vollständige Form. Es ist durchaus üblich, dass Datensatzdefinitionen, gemeinsame Flags, Host-Variablen für SQL und externe Schnittstellen in Copybooks stecken. Ist der Code so schwer lesbar, prüfen Sie am schnellsten, ob Sie an die expandierte Quelle oder ein Compiler-Listing herankommen. IBM Enterprise COBOL bietet dafür auch die Option MDECK, mit der die Eingabequelle nach der Bibliotheksverarbeitung ausgegeben wird.
Autorenprofil
Profilseite des Artikelautors.
Go Komura
Geschäftsführer von KomuraSoft LLC
Spezialisiert auf Windows-Softwareentwicklung, technische Beratung und Fehleranalyse, insbesondere bei bestehenden Systemen und schwer reproduzierbaren Störungen.