COBOL auf BS2000: Ein praxisnaher Einstieg

Cobol

Heute geht es los mit echter Programmierung, denn die reine Theorie ist ja langweilig 😉

Inhaltsverzeichnis

1. Workshop: Die erste ?Hello World?-Anwendung in COBOL schreiben und kompilieren

Jede Programmierreise beginnt mit ?Hello World?. Auch auf dem Mainframe ist dies der erste Schritt, um das Zusammenspiel von Code und Kompiler zu verstehen.

Der COBOL-Quellcode (HELLO.COB)

Wir erstellen eine einfache COBOL-Anwendung, die eine Nachricht auf der Konsole ausgibt.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. HELLO.
       AUTHOR. MAINFRM-DEV.
       INSTALLATION. EXAMPLE-AG.
       DATE-WRITTEN. 2023-10-27.
       SECURITY. NONE.

       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 WS-HELLO-MESSAGE     PIC X(20) VALUE 'Hello BS2000 World!'.

       PROCEDURE DIVISION.
           DISPLAY WS-HELLO-MESSAGE.
           STOP RUN.

Speichern Sie diesen Code in einer Datei, z.B. als $SYSLNK.HELLO.COB auf Ihrem BS2000-System.

Kompilieren und Ausführen auf BS2000

Auf BS2000 nutzen wir JCL (Job Control Language) oder SDF-I (Structured Dialog Facility - Interactive) für die Kompilierung und Ausführung. Hier ist ein einfaches JCL-Beispiel:

//LOGON USERID=DEVEL01,PASSWORD=SECRET
//FILE HELLO.COB,LINK=$SYSLNK.HELLO.COB,OPEN=IN
//CALL SYSLNK.COBOL.2000,MODE=M
//PAR COBOL-OPTIONS=NOSOURCE-LISTING
//OBJECT-OUTPUT-FILE HELLO.OBJ
//LISTING-FILE HELLO.LST
//END-FILE HELLO.COB
//
//FILE HELLO.OBJ,LINK=$SYSLNK.HELLO.OBJ,OPEN=IN
//CALL SYSLNK.BINDER,MODE=M
//PAR START-ADDRESS=ENTRY
//MODULE-OUTPUT-FILE HELLO.PRG
//END-FILE HELLO.OBJ
//
//FILE HELLO.PRG,LINK=$SYSLNK.HELLO.PRG,OPEN=IN
//RUN HELLO.PRG
//LOGOFF

Erläuterung der JCL-Schritte:

  1. //FILE HELLO.COB,...: Definiert die COBOL-Quelldatei. $SYSLNK.HELLO.COB ist der volle Pfadname im BS2000-Dateisystem.
  2. //CALL SYSLNK.COBOL.2000,MODE=M: Ruft den COBOL-Compiler auf. SYSLNK.COBOL.2000 ist der übliche Name für das Compiler-Programm. MODE=M bedeutet interaktiver Modus (oder Dialogmodus, je nach Kontext).
  3. //PAR COBOL-OPTIONS=...: Übergibt Optionen an den Compiler, hier z.B. das Unterdrücken des Source-Listings im Ausgabefile.
  4. //OBJECT-OUTPUT-FILE HELLO.OBJ: Legt den Namen der Objektdatei fest, die der Compiler generiert.
  5. //LISTING-FILE HELLO.LST: Legt den Namen der Listing-Datei fest, die Compile-Fehler und andere Informationen enthält (sehr wichtig für die Fehlersuche!).
  6. //CALL SYSLNK.BINDER,MODE=M: Ruft den Binder (Linker) auf, der die Objektdatei in ein ausführbares Programm umwandelt.
  7. //MODULE-OUTPUT-FILE HELLO.PRG: Legt den Namen der ausführbaren Programmdatei fest.
  8. //RUN HELLO.PRG: Führt das kompilierte und gebundene Programm aus.

Nach erfolgreicher Ausführung sehen Sie auf SYSOUT die Ausgabe: Hello BS2000 World!.

2. Datenstrukturen: PICTURE Clause und Datentypen verstehen

Die PICTURE Clause ist das Herzstück der Datendefinition in COBOL. Sie beschreibt die Struktur, den Typ und die Größe eines Datenfeldes. COBOL arbeitet primär mit EBCDIC-Zeichen für alphanumerische Daten und bietet verschiedene interne Formate für numerische Daten.

Alphanumerische Daten (X)

PIC X definiert alphanumerische Zeichen. Jedes X repräsentiert ein EBCDIC-Zeichen.

       01 WS-ARTIKEL-NUMMER    PIC X(10).       *> 10 alphanumerische Zeichen
       01 WS-BESCHREIBUNG      PIC X(50).       *> 50 alphanumerische Zeichen

VALUE SPACES initialisiert ein Feld mit Leerzeichen, VALUE HIGH-VALUES mit den höchsten EBCDIC-Werten, VALUE LOW-VALUES mit den niedrigsten.

Numerische Daten (9, S, V)

Numerische Daten werden mit PIC 9 definiert. S zeigt ein Vorzeichen an, V einen impliziten Dezimalpunkt.

  • 9: Eine Ziffer. cobol 01 WS-MENGE PIC 9(5). *> Fünfstellige Ganzzahl (0-99999)
  • S: Definiert ein Vorzeichen. Bei USAGE IS DISPLAY wird das Vorzeichen oft im letzten Byte codiert. Für interne Berechnungen ist COMP-3 (Packed Decimal) oder COMP (Binary) effizienter und üblich. cobol 01 WS-SALDO-SIGN PIC S9(7). *> Siebenstellige Ganzzahl mit Vorzeichen
  • V: Definiert die Position eines impliziten Dezimalpunkts. Das Zeichen selbst wird nicht gespeichert, sondern dient als Information für Berechnungen. cobol 01 WS-PREIS PIC S9(5)V9(2). *> Fünf Stellen vor, zwei nach dem impliziten Dezimalpunkt, mit Vorzeichen. *> Z.B. -12345.67

Interne Speicherung (USAGE Clause): Um die Speichereffizienz auf dem Mainframe zu erhöhen, nutzen wir USAGE Clauses:

  • DISPLAY (Standard): Jede Ziffer oder jedes Zeichen belegt ein Byte (EBCDIC).
  • COMP-3 (Packed Decimal): Spart Platz, da zwei Ziffern pro Byte gespeichert werden, plus ein halbes Byte für das Vorzeichen im letzten Byte. Ideal für kaufmännische Berechnungen. cobol 01 WS-PREIS-PACKED PIC S9(5)V9(2) COMP-3.
  • COMP (Binary): Speichert Zahlen im Binärformat. Effizient für Zähler und Indizes. cobol 01 WS-COUNTER PIC S9(9) COMP.

Edited-Daten (Z, *, $, B, /)

Edited-Pictures werden verwendet, um numerische Daten für die Anzeige aufzubereiten, z.B. für Reports oder Bildschirmausgaben.

  • Z (Zero Suppression): Unterdrückt führende Nullen. cobol 01 WS-BETRAG-IN PIC 9(5) VALUE 00123. 01 WS-BETRAG-OUT PIC ZZZZ9. *> Ausgabe: " 123"
  • * (Check Protection): Ersetzt führende Nullen durch Sternchen (Sicherheit bei Schecks). cobol 01 WS-BETRAG-IN PIC 9(5) VALUE 00123. 01 WS-BETRAG-OUT PIC ****9. *> Ausgabe: "***123"
  • $ (Currency Symbol): Fügt ein Währungssymbol hinzu. cobol 01 WS-KOSTEN-IN PIC S9(5)V9(2) VALUE 1234.56. 01 WS-KOSTEN-OUT PIC $$,$$9.99. *> Ausgabe: "$1,234.56"
  • B (Blank): Fügt Leerzeichen ein. cobol 01 WS-TEXT-IN PIC X(5) VALUE 'ABCDE'. 01 WS-TEXT-OUT PIC X(5)BBX(5). *> Ausgabe: "ABCDE " (ohne das zweite X(5) hier)
  • / (Slash): Fügt Schrägstriche ein (oft für Daten). cobol 01 WS-DATUM-IN PIC 9(6) VALUE 271023. 01 WS-DATUM-OUT PIC 99/99/99. *> Ausgabe: "27/10/23"

Edited-Felder können nicht in Berechnungen verwendet werden; sie dienen ausschließlich der Ausgabe.

3. Die PROCEDURE DIVISION: Basis-Anweisungen

Die PROCEDURE DIVISION enthält die ausführbare Logik eines COBOL-Programms. Hier definieren wir die Schritte, die unser Programm ausführen soll.

MOVE - Daten übertragen

Die MOVE-Anweisung kopiert den Inhalt eines Datenfeldes in ein anderes.

       WORKING-STORAGE SECTION.
       01 WS-QUELLE          PIC X(10) VALUE 'ORIGINAL'.
       01 WS-ZIEL            PIC X(10).
       01 WS-ANZAHL-SOURCE   PIC 9(3)  VALUE 123.
       01 WS-ANZAHL-TARGET   PIC 9(5).

       PROCEDURE DIVISION.
           MOVE WS-QUELLE TO WS-ZIEL.
           DISPLAY WS-ZIEL.    *> Ausgabe: "ORIGINAL  " (rechts mit Leerzeichen aufgefüllt)

           MOVE WS-ANZAHL-SOURCE TO WS-ANZAHL-TARGET.
           DISPLAY WS-ANZAHL-TARGET. *> Ausgabe: "00123" (links mit Nullen aufgefüllt)

           MOVE SPACES TO WS-ZIEL. *> Feld mit Leerzeichen füllen

Wichtig: COBOL behandelt MOVE je nach Datentypen unterschiedlich (Rechtsbündig/Linksbündig, Auffüllen mit Leerzeichen/Nullen, Truncation).

ADD - Zahlen addieren

Die ADD-Anweisung addiert numerische Werte.

       WORKING-STORAGE SECTION.
       01 WS-WERT1           PIC 9(3) VALUE 100.
       01 WS-WERT2           PIC 9(3) VALUE 25.
       01 WS-SUMME           PIC 9(4) VALUE ZERO.

       PROCEDURE DIVISION.
           ADD WS-WERT1 TO WS-SUMME.
           DISPLAY 'Summe nach erster Addition: ' WS-SUMME. *> Ausgabe: "0100"

           ADD WS-WERT2 TO WS-SUMME.
           DISPLAY 'Summe nach zweiter Addition: ' WS-SUMME. *> Ausgabe: "0125"

           ADD WS-WERT1, WS-WERT2 GIVING WS-SUMME.
           DISPLAY 'Summe mit GIVING: ' WS-SUMME.    *> Ausgabe: "0125"

Die GIVING-Option ist empfehlenswert, da sie das Zielfeld vor der Addition löscht, was Fehler durch alte Werte vermeidet.

SUBTRACT - Zahlen subtrahieren

Die SUBTRACT-Anweisung subtrahiert numerische Werte.

       WORKING-STORAGE SECTION.
       01 WS-TOTAL           PIC S9(5) VALUE 500.
       01 WS-ABZUG           PIC 9(3) VALUE 75.
       01 WS-REST            PIC S9(5) VALUE ZERO.

       PROCEDURE DIVISION.
           SUBTRACT WS-ABZUG FROM WS-TOTAL.
           DISPLAY 'Rest nach SUBTRACT: ' WS-TOTAL. *> Ausgabe: "00425"

           MOVE 500 TO WS-TOTAL.
           SUBTRACT WS-ABZUG FROM WS-TOTAL GIVING WS-REST.
           DISPLAY 'Rest mit GIVING: ' WS-REST.    *> Ausgabe: "00425"

DISPLAY - Daten ausgeben

DISPLAY ist die einfachste Anweisung zur Ausgabe von Daten, typischerweise auf SYSOUT (dem Standardausgabegerät).

       WORKING-STORAGE SECTION.
       01 WS-MESSAGE         PIC X(30) VALUE 'Verarbeitung abgeschlossen.'.
       01 WS-ZAHL            PIC 9(5)  VALUE 42.

       PROCEDURE DIVISION.
           DISPLAY 'Programm startet jetzt.'.
           DISPLAY WS-MESSAGE.
           DISPLAY 'Aktueller Wert: ' WS-ZAHL.

DISPLAY ist primär für Debugging und einfache Nachrichten gedacht. Für formatierte Reports oder Interaktionen mit DMS (Data Management Systems) wie Adabas oder IMS/DB2 verwenden wir spezifischere Methoden.

4. Strukturierte Programmierung mit PERFORM und GO TO (Vor- und Nachteile)

Strukturierte Programmierung ist entscheidend für wartbaren und lesbaren Code, besonders in großen Mainframe-Anwendungen. COBOL bietet hierfür mächtige Werkzeuge wie PERFORM und, mit Vorsicht zu genießen, GO TO.

PERFORM - Modularität und Wiederverwendbarkeit

Die PERFORM-Anweisung ermöglicht es, Prozeduren (Paragraphs oder Sections) aufzurufen und die Kontrolle nach deren Ausführung an die aufrufende Stelle zurückzugeben. Dies fördert Modularität, Wiederverwendbarkeit und Lesbarkeit.

Grundformen von PERFORM:

  1. Einfacher PERFORM: Führt eine Prozedur einmal aus.

           PROCEDURE DIVISION.
               PERFORM 1000-INITIALISIERUNG.
               PERFORM 2000-HAUPTVERARBEITUNG.
               PERFORM 9000-PROGRAMM-ENDE.
               STOP RUN.
       1000-INITIALISIERUNG.
           DISPLAY 'Initialisiere Variablen...'.
           MOVE ZERO TO WS-TOTAL.
           .
       2000-HAUPTVERARBEITUNG.
           DISPLAY 'Führe Hauptlogik aus...'.
           ADD 1 TO WS-ZAEHLER.
           .
       9000-PROGRAMM-ENDE.
           DISPLAY 'Programm beendet.'.
           .
    
  2. PERFORM  TIMES: Führt eine Prozedur eine bestimmte Anzahl von Malen aus. cobol PERFORM 3000-DATEN-SATZ-VERARBEITUNG 5 TIMES.

  3. PERFORM  UNTIL: Führt eine Prozedur aus, solange eine Bedingung erfüllt ist (oder bis sie nicht mehr erfüllt ist). cobol PERFORM 4000-SCHLEIFE-VERARBEITUNG UNTIL WS-ZAEHLER > WS-MAX-ANZAHL.

  4. PERFORM VARYING: Eine mächtige Schleifenkonstruktion, oft für Tabellenverarbeitung. cobol PERFORM 5000-TABELLEN-ELEMENT-ANZEIGEN VARYING WS-INDEX FROM 1 BY 1 UNTIL WS-INDEX > WS-TABELLEN-GROESSE. Vorteile von PERFORM:

  • Lesbarkeit: Kapselt Logik in benannte Paragraphen, macht den Kontrollfluss klar.
  • Wartbarkeit: Änderungen in einer Prozedur betreffen keine anderen, solange die Schnittstelle (Daten) unverändert bleibt.
  • Wiederverwendbarkeit: Prozeduren können von mehreren Stellen aufgerufen werden.
  • Reduzierung von Duplizierung: Vermeidet, dass derselbe Code an mehreren Stellen geschrieben wird.

GO TO - Fluch oder Segen?

Die GO TO-Anweisung überträgt die Kontrolle bedingungslos an eine andere Stelle im Programm.

           PROCEDURE DIVISION.
               IF WS-FEHLER-FLAG = 'Y'
                   GO TO 9999-FEHLER-ROUTINE
               ELSE
                   PERFORM 2000-NORMALE-VERARBEITUNG.
               .
           9999-FEHLER-ROUTINE.
               DISPLAY 'Ein Fehler ist aufgetreten!'.
               STOP RUN.

Nachteile von GO TO:

  • Spaghetti-Code: Übermäßiger Einsatz führt zu unübersichtlichem, schwer nachvollziehbarem Code mit vielen Sprüngen.
  • Schlechte Wartbarkeit: Änderungen können unerwartete Seiteneffekte haben, da der Kontrollfluss schwer zu verfolgen ist.
  • Debugging-Albtraum: Das Auffinden von Fehlern wird extrem schwierig.

Wann GO TO sinnvoll sein kann (selten!): In einigen sehr spezifischen, seltenen Fällen kann GO TO eingesetzt werden, z.B. um aus tief verschachtelten Strukturen schnell zu einem zentralen Fehlerbehandlungsparagraphen zu springen. Selbst hier wird heutzutage meist eine strukturiertere Fehlerbehandlung (EVALUATE, CALL zu Fehlerroutinen) oder das Setzen eines Status-Flags bevorzugt. Die moderne COBOL-Entwicklung vermeidet GO TO weitestgehend.

Fazit: Setzen Sie auf PERFORM für strukturierten, lesbaren und wartbaren COBOL-Code. Betrachten Sie GO TO als ein Relikt, das in den meisten Fällen durch bessere Designmuster ersetzt werden kann und sollte.