# PS 440

PS 440 ist eine Systemprogrammiersprache für den TR 440. Sie vereint die Vorteile höherer Programmiersprachen gegenüber Assemblersprachen, wie größere Übersichtlichkeit, verminderte Fehleranfälligkeit, höheren Dokumentationswert des Quellprogramms und größere Bequemlichkeit beim Programmieren, mit der Möglichkeit, die Hardware des TR 440 in allen Einzelheiten zu nutzen.
PS 440 wurde an der TU München entwickelt als Hilfsmittel für die Programmierung eines Betriebssystems. Der Hersteller des TR 440 hat den PS‑440-Compiler nicht selbst eingesetzt und auch nicht als Standard-Software vertrieben, aber die Dokumentation in der Schriftenreihe System TR 440 veröffentlicht. Der Compiler wurde von der STARG verbreitet und weiterentwickelt.

## Geschichte

PS 440 wurde von der Arbeitsgruppe für Betriebssysteme der TU München entwickelt als Hilfsmittel zur Programmierung eines Betriebssystems für den TR 440.
Gerhard Goos schrieb die Syntax-Analyse des PS‑440-Compilers mit Hilfe des von ihm entwickelten Parsergenerators SMG (Syntax-Maschinen-Generator). Klaus Lagally schrieb die Codegenerierung. Gerd Sapper brachte den Compiler auf den Betriebssystemen zum Ablauf. Das Ergebnis ist in Bericht 7002 (I. Teil des PS‑440-Handbuchs) dokumentiert.
Helgrit Wich erstellte ein Skriptum zu einem Programmierkurs von Klaus Lagally und Gerd Sapper, daraus ist dann Bericht 7106 (II. Teil des PS‑440-Handbuchs) entstanden.
In der Software-Entwicklung für Großrechner bei AEG-Telefunken wurde PS 440 nicht eingesetzt, da hier schon frühzeitig die Verwendung der höheren Programmiersprache BCPL an Stelle einer Assemblersprache verfolgt wurde. 1972 erschien das PS‑440-Handbuch in der Serie System TR 440 bei Telefunken Computer. Der Compiler wurde über den Arbeitskreis Programmaustausch der STARG verbreitet.
1976 wurde in Stuttgart im Rahmen einer studentischen Semesterarbeit die Testhilfe Trace für PS 440 ergänzt, wie von anderen Compilern des TR 440 gewohnt.
Mit der Ausmusterung der letzten TR 440 Mitte bis Ende der 80er-Jahre endete naturgemäß die Anwendung der Sprache PS 440.

## Programmstruktur

Der Compiler bildet die PS‑440-Quelle auf die Telefunken-Assemblersprache TAS ab; die nicht durch die Sprachmittel von PS 440 abgedeckten Systemfunktionen können durch Einschübe von TAS-Sequenzen genutzt werden. Die erzeugte TAS-Quelle kann anschließend in der üblichen Weise assembliert und montiert werden. Der PS‑440-Compiler ist ein Single-Pass-Compiler; der TAS-Assembler fungiert als zweiter Durchlauf der Compilation. Diese Konstruktion hat folgende Konsequenzen:
* Ein PS‑440-Programm besteht aus einem oder mehreren, an einander gereihten (nicht geschachtelten), Segmenten. Bezeichner sind lokal in einem Segment gültig; Bezeichner, die als global gekennzeichnet sind, gelten im gesamten Quellprogramm. Bezeichner aus anderen Programmmoduln können per Extern-Vereinbarung erreicht werden, selbständige globale Bezeichner können als Eingang gekennzeichnet und so für andere Programmmoduln erreichbar gemacht werden; die Externbezüge werden den Eingangsbezeichnern beim Montieren zugeordnet.
* Anweisungen, Deklarationen und Spezifikationen können, getrennt durch Semikolon, in gemischter Reihenfolge niedergeschrieben werden.
* Alle Bezeichner müssen vor ihrer ersten Verwendung deklariert oder wenigstens spezifiziert sein, sofern ihre Art nicht aus der Verwendung hervorgeht. Beispiele: eine Marke braucht nicht vorab spezifiziert zu werden, wenn sie in einer Sprung-Anweisung verwendet wird; eine Variable, die in einer konstanten Referenz verwendet wird, kann auch weiter hinten im Programm deklariert sein.
* Selbständige Bezeichner aus PS‑440-Deklarationen können in den TAS-Einschüben verwendet werden. In TAS deklarierte Bezeichner sind dagegen außerhalb der TAS-Einschübe unbekannt. Am besten deklariert man alle benötigten Bezeichner mit PS‑440-Sprachmitteln (außerhalb von TAS-Einschüben).
* Als quellsprachbezogener Dump kann der TAS-Dump verwendet werden.
In PS 440 gibt es 97 reservierte Schlüsselwörter, die als Delimiter, Deklaratoren, Operatoren und Bezeichnungen der Hardware-Register fungieren.
Die Syntax in der Tradition der Algol-ähnlichen Sprachen macht insbesondere Anleihen bei Algol 68 und umfasst die üblichen Bausteine der strukturierten Programmierung.

## Datentypen

Entsprechend der Datenstruktur des TR 440 kennt PS 440 nur drei Datentypen:
* SHORT Halbwort mit 24 Bit Länge,
* FULL Ganzwort mit 48+2 Bit Länge,
* LONG Doppelwort mit 2×(48+2) Bit Länge.
Größen dieser Typen können in einem passenden Register oder im Hauptspeicher liegen; im Speicher haben die Halbwörter fortlaufende, die Ganz- und Doppelwörter gerade Adressen. Für alle Operatoren ist festgelegt, auf welche dieser Typen sie anwendbar sind und welchen dieser Typen sie als Ergebnis liefern. Für Zwischenergebnisse in komplexen Ausdrücken wählt der Compiler Register oder Speicherzellen passender Länge aus.
Weitere Datentypen differenzieren anhand des Zugriffsmechanismus:
* INDEX wird zur Deklaration von Halbwörtern im Index-Speicher benutzt: In Ausdrücken verhalten sie sich wie SHORT-Größen, der Speicherzugriff erfolgt jedoch über spezielle Befehle.
* PART ist ein beliebiger, durch eine Bitmaske gesteuerter, Ausschnitt aus einer FULL-Größe; in Ausdrücken wird eine PART-Größe als Ganzwort (wie eine FULL-Größe) weiter verarbeitet.
* LABEL, PROC und PROCSFB beziehen sich auf Halbwort-Adressen in der Befehlszone; sie können Ziel eines Sprunges oder eines Prozeduraufrufs sein.
Den Datentypen im Sinne höherer Programmiersprachen, wie bool, int, real und bytes in Algol 68, sind in PS 440 keine unterschiedlichen Datentypen zugeordnet; vielmehr wird die Interpretation der Daten teils anhand ihres aktuellen Wertes (nämlich ihrer Typenkennung) bestimmt, teils anhand der Operationen, die man auf sie anwendet.

### Typenkennung

Jedes Ganzwort enthält neben den 48 Bit der eigentlichen Information noch 2 Bit als Typenkennung mit folgender Bedeutung:
* Gleitkommazahlen haben im Ganzwort TK=0 (im Doppelwort TK=0 im ersten, TK=1 im zweiten Teil);
* Festkommazahlen haben TK=1 (im Doppelwort zweimal);
* Befehle belegen Halbwörter innerhalb von Ganzwörtern mit TK=2;
* je sechs Textzeichen belegen normalerweise ein Ganzwort mit TK=3.
Literale legen durch ihre Form die Typenkennung implizit fest, so erzeugen etwa die Literale 1.618 und 6.022⏨23 Ganzwörter mit TK=0, die Literale 5 und -2 Ganzwörter mit TK=1 und das Literal "PS 440" ein Ganzwort mit TK=3; Bits-Angaben wie '2H 0003 AFFE' enthalten (links vom H) die gewünschte Typenkennung.
Typenkennungen können mit den Operationen TK0, TK1, TK2 und TK3 gesetzt und mit der Operation TK abgefragt werden.

### Operationen und Operanden

Einige Operationen verhalten sich unterschiedlich, je nach der Typenkennung ihrer Operanden. So vergleichen etwa die Vergleichs-Operationen >, ≥ =, ≠, ≤ und < zwei Operanden mit TK=0 als Gleitkommazahlen (mit Berücksichtigung von Exponent und Vorzeichen), zwei Operanden mit TK=1 als Festkommazahlen (mit Berücksichtigung des Vorzeichens) und zwei Operanden mit TK=2 oder TK=3 als positive Festkommazahlen. Auch die Wirkung der Verschiebe-Operationen LEFT, RIGHT, LEFTC und RIGHTC hängt von der Typenkennung ihres linken Operanden ab.
Bei anderen Operationen entscheidet die Wahl des Operator-Zeichens, welche Variante gewünscht ist. So gibt es beispielsweise unterschiedliche Operatoren für die arithmetischen Operationen, etwa * für die Festkomma-Multiplikation und ** für die Gleitkomma-Multiplikation. Diese Operationen lösen eine Programmunterbrechung, den TK-Alarm, aus, wenn ihre Operanden die falsche Typenkennung haben. Die Operatoren ET, VEL und AUT verknüpfen ihre Operanden bitweise.
Die Wertoperatoren SVAL, FVAL und LVAL fassen ihren (einzigen) Operanden als Adresse eines Halb-, Ganz- bzw. Doppelworts im Speicher auf und liefern dessen aktuellen Inhalt; entsprechend liefert IVAL den Inhalt einer Indexspeicherzelle (ein Halbwort). Umgekehrt liefert der Referenz-Operator REF, der nur auf einen Operanden im Speicher angewandt werden kann, dessen Adresse.

### Ausdrücke

Formeln beschreiben die Berechnung von Werten aus einfachen Operanden. Sie folgen der üblichen Syntax mit Infixnotation für binäre und Präfixnotation für unäre Operatoren mit den üblichen Prioritäten und mit runden Klammern, wo die normalen Operator-Prioriäten nicht passen. Alle Ausgangs-, Zwischen- und Resultatwerte haben eine inhärente Länge gemäß einem der drei Datentypen und werden bei Bedarf verlängert oder verkürzt.
Da PS 440 keinen booleschen Datentyp kennt, kann ein Vergleich keine Formel sein, sondern ist eine Bedingung: Bedingungen steuern Fallunterscheidungen und Wiederholungen, liefern aber im Gegensatz zu Formeln keinen Wert, der gespeichert oder mit dem weitergerechnet werden kann. Die Grundbausteine der Bedingungen sind Vergleiche und Tests. Die Alarmtests TKAL (Typenkennungs-Alarm) und ARAL (Arithmetischer Alarm, d. h. Arithmetischer Überlauf erkannt) haben keinen Operanden, die Typenkennungs- und Bit-Tests haben zwischen dem Operatorsymbol und dem Operanden noch eine TK- bzw. Bit-Nummer, zum Beispiel: IF TK 1 RA THEN RA := −RA FI; diese Nummer muss explizit (nicht als Formel) angegeben werden. Vergleiche und Tests können mit den logischen Operatoren ¬, ∧ und ∨ zu komplexen Bedingungen verknüpft werden.

## Deklarationen und Spezifikationen
### Selbständige Vereinbarung

Die mit selbständigen Vereinbarungen definierten Bezeichner können auch in TAS-Einschüben verwendet werden und erscheinen gegebenenfalls im Trace und im TAS-Dump.
Eine Typvereinbarung bestimmt Typ und Speicherort von Variablen oder Konstanten; für Variable kann ein Anfangswert, für Konstanten muss der Wert angegeben werden. Eine Indexspeicher-Vereinbarung bestimmt nur den Speicherort von Indizes; die sind immer ein Halbwort lang, immer variabel und haben keinen definierten Anfangswert. Eine Typ- oder Indexspeicher-Vereinbarung kann mit einer Wertzuweisung kombiniert werden, die dann – im Gegensatz zum statischen Anfangswert – zur Laufzeit des Programms ausgeführt wird.
Eine Prozedurvereinbarung definiert ein Unterprogramm. PS 440 kennt weder Prozedur-Parameter noch Funktionswerte: Wie in maschinennaher Programmierung üblich, muss die Informationsübergabe zwischen rufendem Programm und Prozedur über den Hauptspeicher oder die Register organisiert werden. Falls eine Prozedur rekursiv aufgerufen werden soll, muss sie auch den Keller für ihre lokalen Variablen explizit organisieren. Entsprechend den beiden Aufrufmechanismen unterscheidet PS 440 auch PROC- und PROCSFB-Vereinbarungen.
Marken werden dadurch vereinbart, dass sie an der entsprechenden Stelle im Programm gesetzt sind (mit nachfolgendem Doppelpunkt).
Beispiele:

### Äquivalenz-Vereinbarung

Mit einer Äquivalenz-Deklaration wird einem neuen (unselbständigen) Bezeichner eine Bedeutung, bestehend aus Typ und Zugriffsmechanismus, zugewiesen, indem er einer bereits deklarierten Größe (oder einer Komponente davon) gleichgesetzt wird. Beim Zugriffsmechanismus können indirekte Adressierung, Indizierung und Teilwortzugriffe verwendet werden; diese Mechanismen werden dynamisch ausgewertet. Eine Äquivalenz-Deklaration kann auf bereits deklarierte selbständige oder unselbständige Größen Bezug nehmen; letztlich muss eine Kette von Äquivalenzen immer auf eine selbständige Größe führen. Die folgenden Beispiele beziehen sich auf die oben deklarierten selbständigen Größen:
Selbstverständlich können auch Teilwort-Zugriffe mit Indizierung und indirekter Adressierung kombiniert werden. Diese Äquivalenzvereinbarungen erleichtern das Programmieren des TR 440 erheblich, wie das unten stehende Unterprogramm für Fortran-Programm illustriert.

### Spezifikation

Eine Spezifikation macht die Eigenschaften einer selbständigen Größe bekannt, deren Speicherplatz an anderer Stelle deklariert wird: Eine eigentliche Spezifikation kündigt eine Vereinbarung im selben Programm an und ermöglicht damit die Compilation in einem Durchlauf; eine Extern-Vereinbarung hat (trotz des abweichenden Namens) dieselbe Funktion für eine selbständige Größe, die in einem anderen Programmodul vereinbart ist. Eine Eingangs-Spezifikation ermöglicht einem anderen Programmodul, sich auf eine selbständige Größe des vorliegenden Programms zu beziehen. Extern-Vereinbarungen und Eingangs-Spezifikationen für Indizes oder Register sind nicht möglich. Die folgenden Beispiele beziehen sich auf die oben deklarierten selbständigen Größen:

## Anweisungen
### Einfache Anweisungen
#### Wertzuweisung und Tausch

Die Wertzuweisung weist einer Variablen einen neuen Wert zu; im Gegensatz zur statischen Vorbelegung mit PRESET wird die Wertzuweisung zur Laufzeit des Programms ausgeführt. Wie in Algol 68 gilt die Wertzuweisung als Ausdruck, kann also Teil einer Formel oder rechter Teil einer weiteren Wertzuweisung sein. Erhöhungen und Erniedrigungen (siehe Beispiele) ergeben besonders effizienten Maschinencode.
Der Tausch vertauscht die aktuellen Werte zweier Variablen. Beide Variable müssen dieselbe Länge haben; Indizes können nur mit anderen Indizes oder dem Register BB getauscht werden. Der Tausch gilt nicht als Ausdruck, kann also – im Gegensatz zur Wertzuweisung – nicht Teil einer Formel sein.
Beispiele:

#### TAS-Einschub

Ein TAS-Einschub fügt die angegebenen Informationseinheiten in die erzeugte TAS-Quelle ein. Damit können Assembler- oder Hardware-Funktionen genutzt werden, für die keine eigenen PS‑440-Sprachmittel vorgesehen sind.
Beispiele:

#### Ausnahmen von der fortlaufenden Befehlsausführung

Ein Prozeduraufruf führt ein Unterprogramm aus. PS 440 unterscheidet zwei unterschiedliche Mechanismen zum Prozeduraufruf, entsprechend den Befehlen SU und SFB. Der SU-Befehl und die entsprechende Rückkehr ins rufende Programm führen automatisch einen Keller der Rücksprung-Adressen im Index-Speicher; deshalb können CALL-Prozeduren, die keine lokalen Variablen benutzen, auch ohne explizite Keller-Organisation rekursiv aufgerufen werden.
Die EXEC-Anweisung führt einen Maschinenbefehl aus, der in einem Halbwort steht. Dies wird u. a. zur Parameterversorgung von Unterprogrammen genutzt.
Sprung und Rückkehr setzen den Programmlauf an anderer Stelle fort und sollten daher nur für Sonderfälle eingesetzt werden. Normalerweise erfolgt die Rückkehr aus einer Prozedur an deren Ende ohne explizite Rückkehr-Anweisung.
Die Leere Anweisung ist unsichtbar und wirkungslos, etwa wenn in einem Zweig einer Fallunterscheidung nichts zu tun ist.
Beispiele:

### Strukturierte Anweisungen

Die Anweisungen einer Sequenz werden durch Semikolon getrennt und können bei Bedarf mit BEGIN und END eingeklammert werden. Nach dem END darf ein Bezeichner als Kommentar geschrieben werden, um auf den Anfang der Sequenz hinzuweisen.
Die Fallunterscheidung gibt es als IF- und als CASE-Anweisung. Die IF-Anweisung muss mit FI abgeschlossen werden; so wird das Dangling Else vermieden und Sequenzen in THEN- oder ELSE-Zweig müssen nicht eingeklammert werden. Die CASE-Anweisung unterscheidet Fälle aufgrund eines ganzzahligen Ausdrucks; hier müssen gegebenenfalls Sequenzen, die einzelnen Fällen zugeordnet sind, eingeklammert werden.
Die Wiederholung kann durch eine Zählung oder durch eine Bedingung gesteuert werden; soll eine Sequenz wiederholt werden, muss sie mit BEGIN und END eingeklammert werden. Alle Wiederholungen sind vorprüfende Schleifen.
Beispiele:

## Vollständige Beispiele

Die folgenden Beispiele zeigen die PS‑440-Sprachmittel im Zusammenhang aus Benutzersicht (keine Systemprogramme). Da es derzeit keine Möglichkeit gibt, PS‑440-Programme zu testen, könnten sie Fehler enthalten.
Das PS‑440-Handbuch enthält als Anhang 2 ein ausführliches Beispiel für ein vollständiges Programm.

### Selbständiges Benutzerprogramm

Das aus der folgenden Quelle erzeugte Programm kann im Benutzer-Auftrag mit dem normalen STARTE-Kommando aktiviert werden und schreibt dann den Text „Grüß Gott!“ ins Ablaufprotokoll (und im Dialogbetrieb an die Konsole des jeweiligen Benutzers).
Die fünf Angaben, die das Betriebssystem zum Start eines Programms im Benutzer-Auftrag benötigt, müssen in TAS-Einschüben gemacht werden. Auch die Systemdienste (SSR-Befehle) werden in TAS-Einschüben aufgerufen. Im Falle eines SSR-Fehlers oder eines Alarms (mit denen hier nicht zu rechnen ist) würde das Programm bei der Marke CIAO fortgesetzt, also ohne Weiteres beendet werden.
SSR-Befehle erwarten die Adresse eines Versorgungsblocks im Register BB. Die Art der gewünschten Systemleistung wird durch die beiden Adressteile des SSR-Befehls bestimmt, die Einzelheiten durch den Inhalt des Versorgungsblocks.
Alle Variablen, Konstanten und Befehls-Adressen werden mit PS‑440-Sprachmitteln deklariert; die deklarierten Namen können in TAS-Einschüben verwendet werden (hier: VIA, CIAO und INDIZES).
Die Äquivalenz-Vereinbarung in Zeile 13 erklärt VB012 als Alias für das erste Ganzwort aus VB616. Eine Spezifikation LABEL CIAO ist unnötig, da CIAO nur in einem TAS-Einschub und in einer konstanten Referenz verwendet wird; da genügt es, dass die Marke CIAO irgendwo im Segment gesetzt ist.

### Unterprogramm für Fortran-Programm

Das folgende Unterprogramm kann aus einem Fortran-Programm mit der Anweisung CALL JETZT (JAHR, MONAT, TAG, STUNDE, MINUTE, SEKUNDE) aufgerufen werden. Als aktuelle Parameter sind 1 bis 6 INTEGER-Variable (oder Feldelemente) anzugeben, in die JETZT das aktuelle Datum samt Uhrzeit einträgt. Überzählige Parameter werden ignoriert. Das Unterprogramm lässt INTEGER*2- und INTEGER*4-Parameter zu und veranlasst bei falscher Versorgung den Abbruch des Programmlaufs mit einer Fehlermeldung.
Der Vorteil von PS 440 gegenüber TAS: Man übersetzt die Struktur der diversen Versorgungs- und Kontrollblöcke aus der Dokumentation als Äquivalenz-Deklarationen ins PS‑440-Programm und muss sich dann beim Zugriff auf die so deklarierten Größen keine Gedanken um indirekte Adressierung, Indizierung und Teilwort-Zugriffe machen, da das alles der Compiler berücksichtigt. Entscheidend dabei ist, dass sich die Äquivalenzen auf veränderliche Adressen beziehen können, die erst zur Laufzeit des Programms ausgewertet werden.
Da das Unterprogramm mehrfach vom selben Programm aufgerufen werden kann, sind Vorbelegungen mit PRESET nur soweit verlässlich, wie sie durch das Unterprogramm selbst nicht verändert werden. Andernfalls muss es den Variablen ihren Anfangswert dynamisch zuweisen – ausgenommen FTADR, das nur für eine Fehlermeldung verändert wird, von der es keine Rückkehr ins rufende Programm gibt.
Das Unterprogramm JETZT wird gemäß Programmiersystem-Konvention mit dem SFB-Befehl aufgerufen, der die Rückkehradresse ins BB-Register bringt; der PS‑440-Compiler erwartet, dass beim Verlassen der Prozedur die Rückkehradresse wieder in BB steht. Also muss am Anfang BB gerettet und am Ende wiederhergestellt werden. Der STRUKT-Pseudobefehl ist ein Hinweis für die Rückverfolgung; aufgrund dieser Angabe erwartet der Rückverfolger im Alarm- oder Fehlerfall die Rückkehradresse im Kontrollblock. Der sonstige Inhalt des Kontrollblocks wird von dem Fehler-Unterprogramm ausgewertet, dessen Adresse im Parameterblock übergeben wurde; diesem Unterprogramm muss im RH-Register die Adresse eines Halbworts, das rechtsbündig die Adresse des Kontrollblocks enthält, übergeben werden.
Beim Aufruf eines Unterprogramms aus höheren Programmiersprachen steht die Adresse des Parameter-Blocks im RA-Register; diese muss als Nächstes gerettet werden. Der Parameter-Block besteht aus einem Kopfwort mit allgemeinen Angaben, gefolgt von je zwei Halbwörtern (Haupt- und Zusatzversorgung) pro Parameter. Die Zusatzversorgung beschreibt Typ und Art des jeweiligen Parameters und damit auch implizit die Wirkung der Hauptversorgung; im Falle eines Feldelements oder einer einfachen Variablen ist die Hauptversorgung ein Befehl, der dessen bzw. deren Adresse ins BB-Register bringt.
Ein Unterprogramm, das aus höheren Programmiersprachen aufgerufen wird, kann die Indizes 0 bis 7 für eigene Zwecke benutzen, sofern es nicht seinerseits andere Unterprogramme aufruft, die diese Indizes verändern. JETZT benutzt insgesamt fünf dieser acht Indizes.