 Hallo, ich bin Harbrock und ich erzähle euch jetzt ein paar Geschichten aus der Kobel-Gruft. Ein bisschen zu meiner Person. Ich arbeite mittlerweile mehr als 15 Jahren bei einer Versicherung in der Datenverarbeitung als Softwareentwickler und hatte mehr als 10 Jahre mit Kobel zu tun oder war nur Kobel-Entwickler oder derzeit arbeite ich aber nur noch selten mit Kobel-Programmen. Im Laufe der Zeit sind aber einige Sachen aufgefallen, die mir auf den ersten Blick sehr seltsam hervorkamen, die aber mit der Überlegung, wo das Ganze herkommt bzw. wann die Sprache entstanden ist, einen gewissen Sinn ergeben haben, aber trotzdem veraltet waren, als ich Programmieren gelernt habe. Dann schauen wir uns mal die Eigenschaften der Sprache an. Die Sprache ist nicht k-sensitiv, die Idee ursprünglich war, dass jede Anwärtsung nach einem Satz in der normalen Sprache bildet und einen Satz schließt man mit einem Punkt ab, sodass das auch für jede Anweisung gilt. Dieser Punkt wird später noch wichtig, er stellt nämlich auch eine gewisse Federquelle dar. Die Idee war, dass die Sprache leicht verständlich sein sollte, also dass man sie im Grunde wie normales Englisch lesen können soll. Deswegen sind viele Füllwörter möglich, die man aber auch problemlos weglassen kann. Was mir im Laufe der Zeit aufgefallen ist, manche Anweisungen sind sehr mächtig. Das heißt, eine Anweisung kann viele Sachen gleichzeitig machen. Da komme ich später noch mal drauf. Von wann ist die Sprache? Also der aktuelle Sprachstandard ist von 2014. Zur Erinnerung, im gleichen Jahr ist File gelandet und Facebook hat WhatsApp gekauft. Der Standard davor war aus dem Jahr 2002. In dem Jahr wurde die Boran 101 zerstört. Das war der Servettische Raumgleiter, der tatsächlich im All war. Und der Euro wurde eingeführt. Mit diesem Standard kam bei Kobol auch eine Unicode-Unterstützung dazu und eine Sprachvariante für objektorientiertes Kobol. Für mich hat das immer den Eindruck eines Marketingbegriffs gemacht, da die Sprache so viel Eigenschaften hat, die mit Objektorientierung eigentlich nicht zusammengehen, dass ich mich damit nie größer beschäftigt habe. Der Standard davor war 1985. In diesem Jahr wurde der Raumsonne DiGiotto gestartet und sowohl der Amiga als auch Tetris sind auf dem Markt erschienen, wie man an den Jahreszahlen jetzt schon sehen kann. Das ist etwa alle zehn Jahre kommt Standard dazu. Der Mitte der 90er ist aus irgendeinem Grund entfallen. Davor war der 1974er Standard. In dem Jahr wurde der erste Satellit der Europäer gestartet, also der erste Satellit überhaupt der WEDA von den USA noch zur Sowjetunion gestartet wurde und der immer noch bekannte Wissenschaft, die Taschenrechner HP 65 erschienen. Wir sind aber immer noch nicht beim ersten Standard. Der erste Ansehstandard war aus dem Jahr 1968. In diesem Jahr ist die erste bemannte Apollo 7 geflogen und die Firma Intel wurde gegründet. Der erste Koboltstandard überhaupt ist das Jahr 1960. In diesem Jahr hat die Sowjetunion die Hunde Belka und Strelka ins All geschickt und das waren noch die ersten Lebewesen, die wohl bald wieder auf der Erde angekommen sind und der Rubinlaser als erster Laser überhaupt wurde in diesem Jahr auch entwickelt. Was auch noch relevant ist, die gesamten Standards sind abwärtskompatibel, also auch Anweisungen, die seit mehreren Standards als veraltet gekennzeichnet werden oder gekennzeichnet sind, werden von aktuellen Compilern trotzdem noch verstanden und die wird man vermutlich auch nie los werden. Dann das Zeilenformat an, was zumindest bei den älteren Standards gültig war. Das kommt von diesem schönen Datenträger hier, der Lochkarte, also pro Zeile 80 Zeichen zur Verfügung, wobei die nicht komplett nutzbar sind, denn zuerst mal vorne fallen sechs Zeichen weg für die Zeilennummer. Das Zeichen in der siebten Spalte, da sind Sonderzeichen, die die ganze Zeile als Kommentar kennzeichnen oder sagen, dass diese Zeile vorne dran fortsetzt oder so oder ähnliches sind, ist also auch nicht nutzbar. Dann gibt es hinten einen reservierten Bereich von acht Zeichen, wo traditionell der Programmname drin stand. Und dann gibt es noch den vorne einen Bereich von vier Zeichen, sogenannten Bereich A, in dem bestimmte Befehle beginnen dürfen, sodass man für die eigentlichen Anweisungen 61 Zeichen pro Zeile hat, dass man damit sich bei der Länge der Variabletnahmen und so weiter eher einschränkt, dürfte verständlich sein. Ja, und mit dem 2002er Standard wurde das Zeilenformat teilweise aufgehoben, mittlerweile gehen also auch längere Zeilen. Trotzdem natürlich, da die Programme sehr alt sein können, findet man häufige Quelltexte, die sich ja trotzdem noch in diesem Standard halten. Genau genommen habe ich bei uns in der Firma noch nie ein Kobel-Programm gesehen, das sich nicht an dieses Zeilenformat hält. So, das Programm ist sehr strukturiert, aufgebaut, also es beginnt mit der Identification Division. Dort stehen grundlegende Informationen wie der Name des Programms, dann kommt die Environment Division, die sozusagen die Umgebung des Programms definiert, in der Configuration Section, zum Beispiel die Änderung, dass nicht der Dezimalpunkt als comma verwendet wird, sondern tatsächlich das comma in Zahlen und in der Input Output Section werden die ganzen Dateien, mit denen das Programm interagiert definiert. Als nächstes kommt die Data Division, als erstes die File Section, wo dann für die vorher definierten Dateien das Datenformat beschrieben wird. Die Working Search Section, wo die ganzen Variablen, die im Programm auftauchen, beschrieben werden. Daran kann man schon erkennen oder sich denken, nein, es gibt keine lokalen Variablen und dementsprechend kann man auch nicht einfach so eine Funktion definieren mit Übergabewerten, außer man definiert den Übergabebereiche, halt auch in dieser Working Search Section. Dann kommt noch die Linkage Section, das ist dann die Datenstruktur, die das Programm beim Aufruf übergeben bekommen kann, wenn es sich um ein Unterprogramm handelt. Und dann schließlich haben wir noch die Procedure Division. In diesem Teil finden sich dann die einzelnen Anweisungen, die man dann auch mit Sections gliedern kann. Da ist man dann in der Benahmung frei. Und natürlich, wenn irgendwelche Sections nicht benötigt werden, dann können sie entfallen. Die Definition von Variablen erfolgt in einer Baumstruktur mit verschiedenen Ebenen. Hier habe ich jetzt mal seine Beispieladresse und eine Summe angelegt. Das sieht dann so aus, dass man mit der Bezeichnung Adresse die gesamte Adresse auf einmal anfassen und in einer anderen Variable das kopieren kann. Hier ist jetzt zu sehen Straßennahme mit PIC, abkürzender für PICTCHA, man kann auch PICTCHA ausschreiben. X20 wäre dann 20 beliebige Zeichen, also alphanomerisch und rossanderzeichen und wird hervorbelegt mit Leerzeichen. Dann filler ist ein reserviertes Wort. Da wird dann einfach ein Zeichen gesetzt, was man aber nicht ansprechen kann, um in diesem Fall dann Straßennahme und Hausnummer zu trennen, sodass man, wenn man Straße als Zeichenkette nimmt, den Straßennahme ein Leerzeichen danach die Hausnummer hat. Die Hausnummer ist hier dreistellig numerisch definiert. Im Grunde die gleiche Struktur findet sich auch beim Ort mit Postleitzahl und Ortsnahme. Das Wort filler kann auch einfach entfallen, das kann man auch leer lassen. Das Feld kann man dann genauso weniger ansprechen, außer natürlich man belegte Ort direkt mit einer Zeichenkette, also Postleitzahl auf Filler und Ortsnahme und Summe als Beispiel einer Zahl. In diesem Fall S steht für das Vorzeichen, 9 ist eine numerische Stelle, die 5 in Klammer bedeutete 5 Stellen vor dem Komma, wird das Komma gesetzt, 2 Nachkommastellen und diese Variable wird mit 0 vorbelegt. Wie man hier an Zahlen erkennen kann, beim Sprachdesign war auch ein Kriterium, dass sich die Personen, die die Sprachprogrammieren sollten, dann nicht irgendwie mit Benerdastellung auseinandersetzen müssen, sondern eine Dezimaldarstellung nutzen können. Hier jetzt nochmal die Zeichen, die bei Variable und Definitionen vorkommen können, 9 wäre die Position einer Ziffer, V, die Position wurde dann das Komma in der Zahl gesetzt wird, S für die Positionierung des Vorzeichens, das kann vor oder nach der Zahl stehen, X für ein alphanumerisches Zeichen und A, was man eigentlich nie sieht, nur für ein alphabäisches Zeichen. Ja, bei numerischen Variablen gibt es auch noch die Möglichkeit dahinter Usage zu schreiben, Usage Display, dann wird ein Byte pro Ziffer verwendet mit Usage COMB1, da bekommt man eine Gleitkommazahl einfacher Genauigkeit mit COMB2 und doppelte Genauigkeit mit Pack Decimal oder COMB3, da hat die eine gleiche Bedeutung, wird für jede Ziffer ein halbes Byte verwendet und zusätzlich ein halbes Byte für das Vorzeichen mit binary COMB oder COMB4, da kann man sich aussuchen, wird die Zahl in Dual-Darstellung abgespeichert, zusätzlich gibt es noch Usage Index, dann wird eine vierweite lange Variable definiert, die bei speziellen Befehlen hat eine Indizierung ermöglicht und Usage Pointer, muss ich ehrlich sagen, habe ich auch noch nie gesehen, für eine Speicheradresse. Als weiteres haben wir die Möglichkeit der Druckaufbreitung, also wenn man eine Zahl ausgeben will, hast du das ja einfach lesbar weißt, dann gibt es ein weiteres Variable Format, wo auch wieder 9 für eine Ziffer steht, Z auch für eine Ziffer, wobei bei führende Nullen dieses Feld mit einem Leerzeichen gefüllt wird, einer Sternchen liefert einen sogenannten Schutzstern, bei führende Nullen hat damit man auf dem Ausdrucker nicht nachträglich was manipulieren kann, minus wird bei einer negativen Zahl mit dem Vorzeichen belegt und sonst mit Leerzeichen und plus wird das Vorzeichen immer belegt und minus oder plus kann man auch mehrfach zum Beispiel vor einer Zahl ersetzen und dann funktioniert das genauso wie das Z, das heißt das Vorzeichen wird dann möglichst eine Zahl herangebrückt und davor mit Blänk belegt. Unten da noch ein paar Beispiele, wenn man die Zahl minus 12,34, jetzt sind die eine Variable mit der Druckaufbereitung minus 9,9999 schreiben würde, hätte man als Ausgabe minus 0,012,34, darunter mit dem führenden Blänk, darunter ein Beispiel, dass das Vorzeichen auch hinter der Zahl stehen kann und ganz unten, wie das mit Schutzsteinchen aussehen. Natürlich ist die Konvertierung zwischen den verschiedenen Zahlenformaten nicht automatisch oder nur in engen Grenzen. Das heißt ich kann eine Zahl, die näher abgespeichert ist, nicht einfach in eine Variable mit Druckaufbereitung kopieren, sondern muss sie erst in eine Variable mit der Usage Display kopieren, das geht und diese Variable kann ich dann in eine Druckaufbereitete Variable kopieren. An arithmetischen Operationen gibt es add, divide, multiply, subtract, compute und move habe ich da jetzt auch dazu genommen. Die oberen vier sind jeweils speziell für die Rechenoperation und auch hier gibt es mehrere Darstellungen, wie unten zu sehen ist, also divide foo into bar, teilt bar durch foo und weiß das wieder der variable bar zu, divide foo into bar giving erg, teilt auch bar durch foo und weiß das der variable erg zu, divide foo by bar giving erg, teilt nicht bar durch foo, sondern foo durch bar und weiß das erg zu. Das Ganze mit der Computanweisung darunter erg gleich foo durch bar ist eine kürzere Schreibweise und zusätzlich kann man dann auch gleich mehrere Operationen hintereinander durchführen, so dass man normalerweise compute nimmt, weil es einfach weniger zu schreiben ist. Allerdings und move den einfach dazu den Inhalt einer Variable in einer anderen zu kopieren. Allerdings sind die einzelne Operationen durchaus mächtig, wie hier zu sehen ist, divide foo by bar giving erg, rounded, reminder rest on size error an Weisung 1, not on size error an Weisung 2. Also es wird foo durch bar geteilt, gerundet und erg zugewiesen. Der Rest der Division wird nach Rest geschrieben, falls ein Variablenüberlauf passiert sein sollte, wird Anweisung 1 ausgeführt, sonst wird Anweisung 2 ausgeführt und das Ganze abgeschlossen mit end divide. Ja, dann move hat auch einige Möglichkeiten. Es kann nämlich ja nicht nur einzelne Variablen oder halt also einen ganzen Zweig des Baums in eine andere Variable kopieren, sondern es hat auch die Möglichkeit move corresponding foo to bar oder kürzereschreibweise move core foo to bar. Das nimmt aus der Datenstruktur foo diejenigen Variablen, die weiter unten im Baum stehen und genauso heißen wie Variablen in der Datenstruktur bar und kopiert die rüber. Also in diesem Fall aufpassen, dass man nicht in einer der beiden Datenstrukturen eine Variable umbenennt, die von dieser Operation betroffen ist, sonst viel Spaß bei der Fehlersuche. Außerdem kann move auch noch zum Initialisieren von Variablen genutzt werden. Also move all zeros to erg, man schreibt nuller in das Feld erg, move all zero to erg, macht genau das gleiche und zeros kann man auch ohne das e hinter dem o schreiben, macht auch genau das gleiche. Zur Manipulation von Zeichenketten gibt es ledigliche drei Anweisungen, inspect, string und unstring, inspect dient dazu in einer Zeichenkette zu schauen, ob irgendein Zeichen oder eine kürzere Zeichenkette vorkommt oder auch wie oft eine Zeichenkette vorkommt oder an welcher Position sie das erste Mal auftritt. Also auch wieder wie vorhin an divide gezeigt, fehlen mit verschiedenen Möglichkeiten. String dient dazu mehrere Zeichenketten hintereinander zu hängen, wobei in diesem Fall dann auch bei jeder Zeichenkette ab einem bestimmten Zeichen abgeschnitten werden kann, um zum Beispiel folgende Leerzeichen zu entfernen. Und unstring zerlegt eine Zeichenkette in mehrere einzelne Zeichenketten auch definiert über die Länge oder über gewisse Trendzeichen oder so. Ja und das war es an Möglichkeiten der Modifikation von Zeichenketten. An Kontrollstrukturen gibt es if evaluate, also heutzutage würde man sagen ein Case Statement, go to, alter, das gehört in diesem Fall zu go to, komme ich gleich darauf zurück, perform und copy. Ein nettes Detail, was mir mal bei evaluate aufgefallen ist in einem Programm, es sind maximal 256 Unterscheidungen möglich. Mit der 257. Unterscheidung kriegt man einen Compile Fehler, ohne dass man diese Begrenzung irgendwo in der Dokumentation finden könnte. Also zumindest ich war nicht erfolgreich. Gut ist vermutlich ein extremer Sonderfall, den ich da hatte. Ja, also if ist klar verfalle Unterscheidungen auf go to, komme ich gleich zurück. Und ja, end if, end perform und end evaluate sind erst mit dem Standardkobel 85 definiert worden. Das heißt, Feuer hat einen Punkt beliebig viele if und evaluate und performen das Statement zugemacht. Also das Zeichen, was man am schlechtesten sieht, war in diesem Fall am mächtigsten. Ja, wenn man aus Versehen einen Punkt aus kommentiert und der Rest trotzdem ein sinnvolles Ergebnis liefert, was aber nicht das Gewünsch tut, hat man auch viel Spaß bei der Fehlersuche. Go to, man kann nicht nur zu einem Label springen, sondern es gibt auch die Möglichkeit go to Label 1, Label 2, Label 3, depending on Zähler. Das heißt wenn Zähler den Wert eins hat, wird zu Label 1 gesprungen, bei 2 zu Label 2 und bei größerem zu Label 3 weiter gibt es den, die Anweisung alter, alter Label 1 to proceed to Label 2. Auch das kann man kürzer schreiben, alter Label 1 to Label 2. Sagt dafür das bei go tos, die nachher ausgeführt werden. Wenn dort steht go to Label 1, dann springt die Ausführung zu Label 2. Und ja, mehrere alter Statements können auch gewissermaßen verkettert werden. Ja, ich hab alter einmal in einem produktiven Programm gefunden. Ich hab ungefähr eine Stunde gebraucht mit einem Handbuch eines Kollegen, bis ich verstanden habe oder bis ich akzeptieren wollte, was diese Anweisung tut. Und dann habe ich auch ungefähr eine Stunde gebraucht, bis ich mit dem Kopfstuckel wieder aufhören konnte. In diesem Handbuch war die Beschreibung das Statements anderthalb Seiten lang. Ungefähr eine halbe Seite war die Beschreibung, was der Befehl tut. Der Rest waren Hinweise der Kategorie auf keinen Fall verwenden. Wir beschreiben es hier nur, falls ihr es in einem alten Programm mal sehen solltet, aber bloß die Finger weg ist böse, der ist verhaltet, soll aus dem Standard gestrichen werden und so weiter und so fort. Perform wird genutzt, um Prozeduren aufzurufen, also wie vorhin bei der Definition schon beschrieben diese Sections im Quelltext werden mit Perform aufgerufen und nach der Ausführung wird dann noch wieder hinter dieses Perform zurückgesprungen. Perform kann aber noch mehr. Mit Perform Anweisung Zäler Times wird eine Vorschleife definiert, also die Anweisung wird Zäler mal aufgerufen, wobei, wenn man einen mitlaufenden Zäler haben möchte, für den Schleifendurchlauf muss man sich den extra definieren. Außerdem deckt Perform die Waldschleife ab durch Perform Prozedur with Test Before, bis zur Bedingung erfüllt ist. Man kann sich was denken. Perform deckt auch die Duwaldschleife ab, im Grunde die gleiche Struktur, nur mit Test After. Es war aber bis in die 80er hinein üblich verschleifen mit If und Go To zu lösen. Kann einem auch etwas Kopfzerbrechen bereiten, wenn man mit so einer Struktur nicht rechnet, weil man es noch nie gesehen hat, aber dann in einem Programm drauf stößt. Als ich sowas das erste Mal gesehen habe, habe ich auch einige Zeit gebraucht, bis ich verstanden habe. Jetzt nochmal auf den Punkt zurückzukommen. Hier sind jetzt drei Quelltexte, die einfache A von B abziehen und das Vorzeichen auf Positiv setzen. Sie sehen auf den ersten Blick gleich bzw. sehr ähnlich aus. Es ist allerdings so, einer der Quelltexte gibt das Ergebnis zweimal aus, einer gibt es einmal aus und einer führt zu einem Compile-Fehler, um das aufzulösen, mal die Endiffs eingefügt. Also der ganz links gibt einmal aus, weil in If der erste Zweig durchlaufen wird, der A größer als B ist. Der zweite gibt das Ergebnis zweimal aus und der dritte führt zu einem Compile-Fehler, da ja dieses L, dieser L-Zweig ohne ein If in der Gegend rumsteht. Wo wir gerade beim Thema Erfehlersuche sind. Also im Falle eines Programmabbruchs, ein Stacktrace, gibt es nicht wirklich, sondern höchstens hat man im Falle das harte Programmabbruchs, den Dump des Speicherinhals und kann dann halt selber auf die Suche gehen, in welcher Zeile das Programm abgebrochen ist, in welcher Variable es liegen konnte bzw. in welchem Wert in der Variable. Wenn man vorher schon damit rechnet, dass man einen Wert brauchen könnte, dann kann man mit der Anweisung Display eine oder mehrere Variablen ausgeben, die in einer Datei bzw. in einer speziellen Datei die Konsole geschrieben werden. Bei Online-Programmen, das sind Programme, die interaktiv bedient werden, in unserem Fall auch von Sachbearbeitern, geht das aber nicht. Da können mehrere Instanzen gleichzeitig laufen und die ganzen Displayausgaben laufen dann im Rechenzentrum auf einer Konsole auf. Als Entwickler sieht man die also nicht, aber die Kollegen im Rechenzentrum fluchen dann eventuell, wenn sie zu viele Ausgaben in dieser Konsole bekommen. Es gibt aber verschiedene Debugger, die unterschiedlich gut zu bedienen sind. Normalerweise hat man auch einen unterschiedlichen Debugger für Online- und Verbetschprogramme. Heutzutage werden die mehr oder weniger gut von der Entwicklungsumgebung unterstützt, damit wir dann zur Entwicklungsumgebung kommen. Herkömmlich war das ein Editor, der auf dem Großrechner lief und im 3270 Terminal bzw. in neueren Fällen in der Terminal-Emulation auf dem PC bedient wurde, also 24 Zeilen zu 80 Zeichen, wobei von den 24 Zeilen oben und unten noch ein paar Verstatusinformationen usw. wegfielen. Das war für mich irgendwie so wie programmieren durch einen Briefschlitz. Im Zweifel sieht man recht wenig, dass ich mir dann normalerweise im Browser das gleiche Programm aufgemacht habe im Online-Repository, weil ich da dann doch 50, 60 Zeilen auf einmal sehen konnte und noch leichter scrollen konnte, um dann noch einen Überblick zu bekommen. Heutzutage gibt es zum Beispiel die IDZ von IBM. IBM hat Developing for Z systems, was eine Eclipse-Umgebung ist mit spezifischen Erweiterungen für den Großrechner, zum Beispiel auch Vercobol. Da hat man dann auch verschiedene Editor-Möglichkeiten. Man kann sowohl einen Editor benutzen, der sich genauso bedient wie der Editor auf einmal Großrechner oder auch Editorinnen, die sich heute übliche Editorinnen bedienen lassen, also mit besseren Suchfunktionen oder Suchn-undersetzen-Funktionen. Dafür aber eventuell nicht so bequem mit der Möglichkeit, nach einem Block von nur ein paar Spalten über mehrere Zeilen zu markieren und zu kopieren. Sonst gibt es auch noch die Möglichkeit von Generatorsprachen, die einem das Leben erleichtern können, die dann durch ein Precompiler geschickt werden, wo man dann halt eine weitere Sprache lernen muss, die einem aber eine Menge Standard-Operationen abnehmen kann. Problem bei denen kann dann aber sein, wenn die neue Entwicklungsumgebung diese Sprache nicht mehr unterstützt oder der Herrsteller der Sprache die Entwicklung keine Unterstützung für die Entwicklungsumgebung gebaut hat, kann es passieren, dass die Programme in dieser Sprache einfach durch ein Precompiler geschickt werden und dann dieser Quelltext abgespeichert wird und man dann in Zukunft mit diesem Quelltext arbeiten muss und dann kann es passieren, dass einem auffällt, okay, die Generatorsprache hat keine sinnvollen Datenstrukturen, oder nein, nicht Datenstrukturen, sondern Programmablaufstrukturen produziert, sondern eine Go-to-Bülste, sodass das Programm was vorher einfacher zu lesen, zu verstehen war, auf einmal viel schwieriger zu verstehen ist. Ja, das war es von meiner Seite. Gibt es noch Fragen und sonst, falls jemand später noch Fragen hat, oder da rund, das sind meine erste Kontaktmöglichkeiten von mir. So, eine Frage und jetzt Mikro. Ja, ich habe deine Frage, du hast die Working Variables erwähnt. Wie würde man, oder wie war das nochmal? Was für Variablen? Die Working Variables oder so was, die Working Storage. Ja, du hast erwähnt, dass es keine Möglichkeit gibt, einer Prozetturparameter zu übergeben. Wie würdest du das damit machen? Die einzige Möglichkeit, die es gibt, ist halt in dieser Working Storage, also bei den globalen Variablen, eine Variable zu definieren, wo halt mal vor dem Aufruf einer Section mit performen der Inhalter reingeschrieben wird, der in dieser Section benötigt wird und dann in der Section weiter verarbeitet wird. Aber daran sieht man schon, rekursive Aufrufe gehen damit nicht. Prinzipiell wäre es auch möglich, eine Variable weiter zu verwenden oder mehrere Stellen zu verwenden. Man müsste halt nur aufpassen, dass in dieser Variable nicht gerade was drinsteht, was später noch gebraucht wird. Also im Selflesfall lieber nach einer weiteren definieren und die Wirkten aufblähen. Und was unterscheidet den Working Storage von anderen Variablen? Es gibt sie im Working Storage. Also lokale Variablen gibt es einfach nicht. Es gibt nur Variablen, Definitionen halt für das Programm, dann Variablen, Definitionen, die über am Aufruf das Programm so belegt werden und Variablen Definitionen für die eine oder andere Ausgabe der Dateien des Programms. Was ich bei den Variablen vergessen habe, ist die Möglichkeit Redefines, wo man ein Dinnerspeicherbereich von einer Variablen oder so einem Teil der Baumstruktur wieder verwenden kann. Man sollte aber natürlich aufpassen, dass wenn man das zum Beispiel als Zeichenkette wieder verwendet, es aber eine numerische Variable ist, dass tatsächlich bei jedem Zugriff auf die numerischen Variable auch eine Zahl drinsteht. Sonst kriegt man einen Laufzeitfehler. Gibt es noch weitere Fragen? Noch jemand eine Frage? Sieht nichts aus, dann bedanke ich mich für die Aufmerksamkeit.