PostScript III:Der Operanden Stack von PostScript: Felder, Variablen, Schleifen und Macro Definitionen

ArticleCategory: [Artikel Kategorie]

Software Development

AuthorImage:[Bild des Autors]

[Photo of the Author]

AuthorName:[Name des Autors]

Emre Demiralp

AboutTheAuthor:[Über den Autor]

Ich bin Student am Istanbul American Robert College und gleichzeitig einer der Administratoren des Computer Labs der "Sciences and Letters Faculty" der Istanbul Technical University. Das dominierende Betriebssystem in diesen Labs ist LINUX. Meine Interessen: PovRay und PostScript, Animation, CD Design, Programmieren, Holographie etc.. Linuxbenutzer seit 1994.

Abstract:[Zusammenfassung]

Jemand, der sehr viel weiß, scheitert auch sehr häufig
-Türkisches Sprichwort-.

Der Autor setzt seine Beschreibung des Operanden Stack der PostScript Sprache fort. In diesem Artikel werden die Definition von Feldern (arrays), Feldoperatoren, Schleifen und Macrodefinitionen recht detailliert und mit illustrativen Beispielen besprochen sowie Aufgaben gestellt, die im nächsten Artikel beantwortet werden. Dieser Artikel behandelt den Operanden Stack nicht abschließend. Das Thema wird in kommenden Artikeln weiter fortgesetzt.

ArticleIllustration:[Titelbild des Artikels]

[Ilustration]

ArticleBody:[Der eigentliche Artikel]

Einführung

Dies ist der dritte Artikel in einer Serie über PostScript. Wir werden uns hier weiter mit dem Operanden Stack von PostScript beschäftigen. In diesem Artikel geht es vor allem um die Definition von Feldern, Feldoperatoren, Variablendefinitionen, Schleifen und Macrodefinitionen. Wir versuchen, das wesentliche darüber darzustellen. Die "Geschichte" über den Operanden Stack geht in zukünftigen Artikeln mit verschiedenen Themen, die in Beziehung zu Operanden Stacks stehen, weiter.

Felder und Feldoperatoren

In den vorangegangenen Artikeln dieser Reihe haben wir bereits die Struktur des Operanden Stacks und die Operatoren, die diese Struktur verändern können, kennengelernt. Wie wir uns erinnern, waren alle Mengen, die im Operanden Stack gespeichert sind, Integer, außer einem speziellen Element, das dazu benutzt wird, Referenzpunkte im Operanden Stack zu erzeugen. Dieses Element wurde -marktype- genannt und seine Operatoren, cleartomark und counttomark, wurden dazu benutzt, die Elemente vom obersten bis zu diesem Element zu löschen bzw. zu zählen. Dies ist natürlich eine Möglichkeit zur Gruppierung, aber nicht die einzige. Es ist möglich, eine einzelne Entität zu erzeugen, die aus vielen Elementen bestehen darf. Diese Entität wird Feld genannt und es ist durch die Feldoperatoren in der PostScript Sprache möglich, mit seinen Elementen zu arbeiten. Im folgenden gehen wir - nach Feldoperatoren geordnet- detailliert auf dieses Thema ein und geben einige illustrative Beispiele.

[  :Dieser Befehl erzeugt ein Markierungselement im Stack (Stapel). Bis sein Gegenstück, ], eingegeben wird, spielt er diesselbe Rolle wie der mark Befehl. Alle Elemente, die auf dem Operanden Stack nach diesem Operator abgelegt werden, werden als individuelle Elemente betrachtet, obwohl es einen gekennzeichneten Referenzpunkt vor ihnen im Operanden Stack gibt. Im folgenden Beispiel wird die Beziehung zwischen [ und mark erklärt.

GS>[ pstack
-marktype
GS<1>2 3 mark pstack
-marktype-
3
2
-marktype-
GS<4>

]  :Dies ist das Gegenstück zu dem obengenannten Operator [. Im Stack muß schon ein Markierungselement vorhanden sein, bevor dieser Operator benutzt werden kann. Tatsächlich wird er als Endmarkierung für das Feld angesehen und schließt die Feldkonstruktion ab. Da jedes Ende einen Anfang braucht, sucht PostScript sein Gegenstück, die Anfangsmarkierung ], sobald das Element in den Operanden Stack eingegeben wird. Wenn [ fehlt, dann gibt PostScript eine Fehlermeldung aus und die gewünschte Aktion wird nicht ausgeführt. Wird dieses Element sofort nach [ in den Operanden Stack eingegeben, dann wird ein leeres Feld erzeugt und als einzelne Entität im Operand Stack gespeichert (das existierende Markierungszeichen ist ein Teil des Feldes, daher erscheint es als anderes Element), wie das folgende zeigt:

GS>[ pstack
-marktype-
GS<1>] pstack
[]
GS<1>

Hiernach enthält der Operanden Stack nur ein einziges Element, ein leeres Feld. Ein nicht-leeres Feld kann direkt durch die Eingabe von [ und ] zusammen mit den Feldelementen in einem einzigen Eintrag in den Interpreter erzeugt werden, wie das folgende Beispiel zeigt.

GS>[ 1 2 3 ] pstack
[1 2 3]
GS<1>

Wie wir sehen, wird das Feld nur als eine einzelne Entität betrachtet.

Wir können auch ein Feld mit einer bestimmten Anzahl von Elementen anlegen, ohne jedes einzelne Element spezifizieren zu müssen. Dies wird durch die Verwendung des null Elements erreicht, das nichts anderes als das folgende bedeutet.

GS>[ null null ] pstack
[null null]
GS<1>

array:Dieser Befehl benötigt einen Integerparameter. Wenn der Parameter n ist, dann lautet der Befehl n array. Dies erzeugt dann ein Feld, das genau n null Elemente enthält. Dasselbe kann man auch mit Hilfe der Anfangs- und Endmarkierungen der Felderzeugung erreichen. Z.B. ist 3 array dasselbe wie[ null null null ]. Der Befehl nimmt das nächst höhere Element aus dem Operanden Stack als Parameter. Wird der Parameter nicht vor dem Befehl eingegeben, dann bestimmt das Element, das sich zu dem Zeitpunkt gerade an oberster Stelle im Operanden Stack befindet, was passiert. Wenn das Element ein Integer ist, dann wird sein Wert von dem Befehl verwendet, ansonsten erscheint eine Fehlermeldung wegen Inkompatibilitäten.

length:Dieser Befehl berechnet die Anzahl der Elemente im Feld. Die null Elemente werden dabei auch mitgezählt. Der Operator benötigt einen Parameter, der ein Feld sein muß. Der Operator nimmt das oberste Element im Operanden Stack als seinen Parameter. Der Parameter verschwindet dann nach der Ausführung der Operation aus dem Operanden Stack. Daher läuft solange alles gut, solange der Parameter ein Feld ist und vor dem Befehl eingegeben wird, und als Ergebnis erscheint eine Zahl als oberstes Element auf dem Operanden Stack. Zum Beispiel:

GS>[ 1 2 3 4 5 ] length pstack
5
GS<1>

Wenn wir vor dem length Operator keinen Parameter eingeben, dann versucht der Befehl, das oberste Element im Operanden Stack zu benutzen. Wenn dies ein Feld ist, dann benutzt er es, das Element wird aus dem Operanden Stack entfernt und die Anzahl der Elemente im Feld erscheint als oberstes Element im Operanden Stack,

GS<1>pstack
[1 2 3 6 7]
GS<1>length pstack
5
GS<1>

ansonsten, wenn es kein Feld ist, wird eine Fehlermeldung ausgegeben.

get:Dieser Operator benötigt zwei Parameter, wobei der erste Parameter ein Feld und der zweite ein Integer sein muß. Der Operator sucht ein spezielles Element aus dem Feld. Die Position des gesuchten Elements ist der zweite vom Befehl benötigte Parameter. Die Positionen sind mit natürlichen Zahlen indiziert, d.h. sie beginnen bei null. Tatsächlich gelten diese Regeln für alle Operatorparameter. Die Parameter werden von dem Befehl benutzt und dann aus dem Operanden Stack entfernt. Ihre Typen müssen mit den vorgegebenen Werten übereinstimmen. Weiter wollen wir darauf nicht eingehen. Die Benutzung von get ist wie folgt.

GS[1 6 3 0 9] 0 get pstack
1
GS<1>

put:Dieser Befehl benötigt drei Parameter. Diese sind ein Feld, ein Index und das Element, das in das Feld eingefügt werden soll. Wenn sie eingegeben wurden, nimmt der Befehl das Feld, das durch den ersten Parameter bestimmt wurde, sucht die Stelle, deren Index durch den zweiten Parameter spezifiziert wurde und ersetzt das Feldelement an dieser Position durch die Eingabe im dritten Parameter des Befehls. Das sich ergebende Feld wird jedoch nicht im Operanden Stack abgelegt. Deshalb kann man für die explizite Benutzung des put Operators eine Feldvariable (oder einen Schlüssel (key) in der PostScript Terminologie) definieren. Die Anwendung wird dann in dieser Variablen ausgeführt und das Ergebnis auf dem Operanden Stack abgelegt und von dort angezeigt. Schau dir das folgende an

GS>[1 2 3] 0 8 put
GS>

Nichts passiert hier innerhalb des Operanden Stacks. Aber es wird auch keine Fehlermeldung angezeigt. In Wirklichkeit tut put, was es tun soll, aber das Ergebnis wird nicht im Operanden Stack gespeichert. Um das Ergebnis derselben Aktion auf den Operanden Stack zu bekommen, müssen wir so vorgehen:

GS>/ar [ 1 2 3 ] def
GS>ar 0 8 put
GS>ar pstack
[8 2 3]
GS<1>

Hier wird zuerst so etwas wie eine Feldvariable oder ein Schlüssel (PostScript Terminologie) definiert. Der Variablenname ist ar. Der zweite Schritt betrifft das Ändern des ersten Elements (mit Index null) in 8 durch den Gebrauch des put Operators (Befehls). Danach fügt ar pstack den Wert der Feldvariablen ar in den Operanden Stack ein und zeigt seinen Inhalt an. Wir werden uns mit der Variablendefinition weiter unten in diesem Artikel befassen. In zukünftigen Artikeln dieser Reihe beschäftigen wir uns auch mit den Verzeichnissen und den Verzeichnisstacks.

getinterval:Dieser Operator erzeugt ein Unterfeld eines gegebenen Feldes. Er benötigt drei Parameter, ein Feld, aus dem das Unterfeld erzeugt wird, einen Index, der das erste Element im Unterfeld festlegt und einen Integer, der die Anzahl der Elemente im Unterfeld angibt. Wenn der Befehl benutzt wird, nimmt der Befehl eine Anzahl von Elementen (bestimmt durch den dritten Paramter) aus dem Feld (das durch den ersten Paramter festgelegt wurde) und kopiert sie, beginnend von der durch den zweiten Parameter spezifizierten Position, in ein neues Feld. Das neue Feld wird in den Operanden Stack eingefügt. Zum Beispiel:

GS>[1 2 3 4 5 6 7 8 9] 2 3 getinterval pstack
[3 4 5]
GS<1>

putinterval:Dieser Befehl ersetzt ein Unterfeld eines vorgegebenen Feldes mit einem vorgegebenen anderen Feld. Drei Parameter werden benötigt. Als erstes das Feld, dessen Unterfeld geändert werden soll, als zweites ein Integer, der die Position des Unterfeldes, das geändert werden soll, angibt und drittens das Unterfeld, das das andere Unterfeld ersetzen soll. Der Befehl ist dem putBefehl sehr ähnlich. Er legt das Ergebnis auch nicht auf dem Operanden Stack ab.

GS>/ar [1 2 3 4 5 6 7 8 9] def
GS>ar 3 [0 0 0] putinterval
GS>ar pstack
[1 2 3 0 0 0 7 8 9]
GS<1>

aload:Dieser Befehl nimmt ein Feld als Parameter und kopiert seine Elemente als einzelne Entitäten in den Operanden Stack. Das oberste Element im Operanden Stack nach der Ausführung ist das Feld. Also,

[1 2 3] aload pstack
[1 2 3]
3
2
1
GS<4>

astore:Dieser Befehl ersetzt alle Elemente eines Feldes, das durch den zweiten Parameter bestimmt wurde, mit einer Folge von Elementen, deren Anzahl mit der Länge des Feldes im Operanden Stack übereinstimmt. Das Ergebnis ist ein neues Feld mit den ersetzten Elementen.

GS>1 2 3 [null null null] astore pstack
[1 2 3]
GS<1>

copy:Dieser Befehl kopiert den ersten Parameter, der ein Feld sein muß, in das erste Unterfeld, das vom zweiten Parameter, der ebenfalls ein Feld sein muß, bestimmt wird. Das angezeigte Ergebnis ist das kopierte Unterfeld, nicht das zweite Feld. Um die letzte Form des zweiten Feldes zu sehen, kann eine Variablendefinition wie folgt durchgeführt werden.

GS>[1 2 3] [4 5 6 7 8] copy pstack
[1 2 3]
GS<1>/ar [4 5 6 7 8] def
GS<1>[1 2 3] ar copy
GS<2>ar pstack
[1 2 3 7 8]
[1 2 3]
[1 2 3]
GS<3>

Die Feldelemente müssen keine Integer sein. Sie dürfen auch Zeichenketten (strings) oder Felder sein. Dies bedeutet, das vernestelte Strukturen von Feldern in PostScript erlaubt sind. Dieser Vorteil ermöglicht es uns, Martrizenoperationen und Macrodefinitionen auf Matritzen anzuwenden. Es ist sogar im Prinzip möglich, Tensoren oder multidimensionale Folgen zu handhaben. Im Moment begnügen wir uns erst einmal mit diesen Informationen.

Schlüssel und Variablen

Es ist in allen Programmiersprachen möglich, Variablen zu definieren. Variablen erleichtern es uns, Mengen zu handhaben, ohne ihren genauen Platz in der Speichereinheit zu kennen. Man kann den in einem Segment der Speichereinheit gespeicherten Wert entweder dadurch erhalten, daß man seine Adresse angibt oder durch Angabe des Schlüssels. Der erste Methode entspricht die Benutzung von Zeigern wie in C ... Wenn du dich mit den Adressen nicht herumschlagen willst, dann ist die Benutzung von Schlüsseln ausreichend. Aber in diesem Fall müssen der Compiler oder der Interpreter der Programmiersprache über den Speicherzugang und andere Operationen wachen. Hierfür definierst du nur ein Wort oder eine Zeichenkette, einen Namen in verständlicher Sprache und weist dieser Entität dann einen Wert zu. Alle diese Aktionen dienen nur dazu, der Programmiersprache zu sagen, was die Variable ist und welchen Wert sie aus deiner Sicht hat. Der Compiler oder Interpreter legt ein Speichersegment für deine Variable fest und alle Zuweisungen gehen als Daten in dieses Segment. Eine ähnliche Strukutr ist auch in PostScript verfügbar. PostScript hat Verzeichnisse, die Namen oder Schlüssel und verwandte Definitionen enthalten. In der PostScript Terminologie ist ein Verzeichnis ein zusammengesetztes Paar, dessen erstes Element Schlüssel und dessen zweites Wert genannt wird. Zum Beispiel ist add ein Name (Schlüssel), der die arithmetische Addition (Wert) durchführt. PostScript kennt die Bedeutung von add, weil sie in einem Verzeichnis, das systemdict genannt wird, gespeichert ist. Wenn du den Befehlt 1 2 add pstack eingibst, bekommst du als Ergebnis 3, weil PostScript diese drei Namen nachschaut und dann das folgende macht: Es findet 1 und 2 und dann add. Die ersten beiden Objekte sind Integer, weshalb sie im Operanden Stack gespeichert sind. Das dritte Objekt ist eine Zeichenkette, die ein Name (Schlüssel) sein kann oder auch nicht. PostScript versucht in seinen Verzeichnissen diesen Namen zu finden. Wenn er gefunden wird, findet die Aktion, die im Verzeichnis definiert ist, statt. Da add in den Systemverzeichnis systemdict existiert, gibt es die Aktion (Wert) für diesen Namen (Schlüssel). Das ist z.B. das Herausnehmen von den obersten zwei Elementen aus dem Operanden Stack, um ihre arithmetische Summe zu berechnen, und dann das Legen des sich ergebenden Wertes als oberstes Element auf den Operanden Stack. Der restliche Teil des Befehls ist die Zeichenkette pstack, die in einem Systemverzeichnis existiert und "gib den momentanen Inhalt des Operanden Stacks als Standardausgabe aus" bedeutet. Deshalb findet diese Aktion statt. Wenn wir aus Versehen oder absichtlich die folgende Zeile in den Interpreter eingeben würden: 1 2 dad pstack, dann würde der Interpreter eine Fehlermeldung ausgeben, weil der Schlüssel oder Name, dad, nicht in den Verzeichnissen von PostScript definiert ist.

Wir sind nicht auf die bestehenden Definitionen des Systemverzeichnisses von PostScript beschränkt. Es ist möglich, einige Prozeduren oder Identifikationen als Aktionen von benutzerdefinierten Befehlen zu definieren. Wenn die Definition eine Identifikation ist, dann bezeichnen wir den Namen oder Schlüssel als Variable, obwohl dies in der PostScript Terminologie nicht vorkommt. Unsere Absicht ist es, Ähnlichkeiten mit anderen gut bekannten Programmiersprachen aufzuzeigen. Für Variablendefinitionen ist alles, was wir tun müssen, /x value def einzugeben, wobei value ein Objekt von PostScript ist, wie integer, array, string ... Laß uns z.B. den Fall betrachten, daß wir /x 12 def im Interpreter Prompt eingegeben haben. Wenn das geschehen ist, dann nimmt der PostScript Interpreter die drei Objekte /x, 12 und def. Die Objekte, die mit einem Schrägstrich beginnen, werden als Schlüssel oder Namen erkannt. Sie können in den Operanden Stack eingefügt werden, ohne daß vorher überprüft werden muß, ob sie in einem Verzeichnis existieren. Der def Befehl existiert als ein Schlüssel-Wert Paar in einem Systemverzeichnis von PostScript und benötigt zwei Parameters, als erstes den Schlüssel oder Namen, der definiert werden soll und als zweites den Wert, der dem Schlüssel zugewiesen werden soll. Deshalb erzeugt PostScript ein Schlüssel-Wert Paar nach diesem Befehl, /x 12 def, gibt es aus und legt es in ein spezielles default Verzeichnis, das laufendes Verzeichnisgenannt wird. Über das oberste Element dieses Verzeichnisstacks werden wir später in dieser Artikelreihe noch ausführlich sprechen. Hiernach wird x von PostScript während der gesamten weiteren Sitzung als 12 erkannt.

Im Prinzip kann jede Zeichenkette, die mit einem Schrägstrich beginnt, als Schlüsselwert verwendet werden. Es ist aber besser, keine Zeichen zu verwenden, die keine Buchstaben oder Zahlen sind. Andernfalls kann es passieren, daß Zeichen wie Punkte, Schrägstriche etc. unerwünschte Aktionen in der Benutzung des Ergebnisschlüssels hervorrufen, weil sie evtl. eine spezielle Rolle in PostScript spielen, wie z.B. der Schrägstrich. Die Beschränkungen an die Anzahl von Zeichen in der Zeichenkette für den Schlüsselnamen sind von den Kapazitäten und Begrenzungen des Interpreters, den du benutzt, abhängig. Tatsächlich ist es aber nicht angenehm, mit einem 100 Zeichen langen Schlüsselnamen zu arbeiten, auch wenn das vielleicht möglich ist. PostScript unterscheidet zwischen Groß- und Kleinbuchstaben, was eine Menge an Flexibilität bringt. Die Namen dürfen nur keine Systemschlüssel von PostScript sein. Ansonsten überschreibt deine Schlüsseldefinition den Systembefehl, was nicht so angenehm ist, z.B., wenn du /add 13 def eingibst und dann feststellen mußt, daß add nur eine Konstante ist und dadurch die Additionsfähigkeit von PostScript während der gesamten weiteren Sitzung blockiert ist. Es gäbe noch viel zu diesen Thema zu sagen, aber wir begnügen uns mit diesem Abschnitt und heben uns den Rest für zukünftige Artikel auf.

Schleifen

PostScript besitzt Wiederholungskonstruktionen, Schleifen genannt. Sie sorgen dafür, daß man eine Anzahl von Ausführungen gleichen Typs durchführen kann. Die Zahl der Ausführungen kann tausend-, millionen- oder billionenfach sein. Es ist egal. In einem einzigen Befehl können durch die Verwendung von Schleifen ganze Prozeduren ausgeführt werden. In diesem Abschnitt geht es um Schleifen und Schleifenbefehle.

repeat:Dieser Befehl benötigt zwei Parameter. Der erste ist ein Integer, der die Anzahl der Wiederholungen bestimmt und der zweite ist normalerweise eine Prozedur, die die Aktionen in Blöcke unterteilt. In PostScript wird ein Block durch seine Begrenzungsmarken, { und }, definiert. Die Instruktionen oder Befehle werden hintereinander zwischen die Begrenzungsmarken geschrieben. Die Syntax dieses Befehls ist wie folgt: n { ... } repeat. PostScript nimmt den ersten Parameter und fügt ihn in den Operanden Stack ein. Dann wird die Prozedur, die als Block { ... } genommen wird, aufgelöst, um ihre Aktionen festzustellen. Schließlich wird repeat gesucht und im Systemverzeichnis gefunden und ausgeführt. Da die definierte Aktion nur eine Wiederholung ist, wird die durch den zweiten Parameter übergebene Prozedur n-mal ausgeführt. Um das noch genauer zu zeigen, hier das folgende Beispiel.

GS>3 {1} repeat
1
1
1
GS<3>

Drei Integerwerte, 1, werden durch diesen Befehl in den Operanden Stack eingefügt. Die Prozedur hier ist wirklich sehr einfach. Sie gibt nur 1 ein. Hier ein anderes Beispiel, das eine etwas kompliziertere Prozedur benutzt.

GS>1 5 {1 add} repeat pstack
6
GS<1>

In diesem Beispiel wird zuerst 1 auf den Operanden Stack gelegt und dann die Prozedur {1 add} 5 -mal auf dem Operanden Stack ausgeführt. Diese 5 -schrittige Ausführung geschieht wie folgt. Im ersten Schritt wird 1 add ausgeführt. add benötigt zwei Parameter, wobei der zweite eine Prozedur ist. Der erste Parameter (oder Operand in der PostScript Terminologie) wird vom Operanden Stack genommen. Deshalb wird im ersten Wiederholungsschritt 1 1 add ausgeführt. Das einzige Element im Operand Stack, 1, wird nach dieser Ausführung gelöscht und das Ergebnis, das 2 ist, als oberstes Element eingefügt. Dann geht es im zweiten Schritt mit 2 1 add weiter und resultiert in einem ein Element enthaltenden Operanden Stack, dessen einziges Element 3 ist. Dieses wird bei der Ausführung der nächsten Wiederholung benutzt. 3 1 add. Die verbleibenden beiden Schritte umfassen die Ausführung von 4 1 add und 5 1 add. Danach, wenn alles ausgeführt ist, ist das einzige Element auf dem Operand Stack 6.

for:Dieser Befehl benutzt eine Steuerungsvariable vom Typ Integer für die wiederholte Ausführung einer gegebenen Prozedur. Die Steuerungsvariable startet von einem gesetzten Anfangswert und erhöht nach jeder einzelnen Ausführung der Prozedur ihren Wert. Diese Aktion wird solange fortgesetzt bis der festgelegte Grenzwert überschritten wird. Deshalb benötigt dieser Befehl vier Operanden, von denen die ersten drei Anfang, Erhöhung und Grenze sind. Alle diese drei Parameter müssen numerische Werte, Integer oder Dezimalzahlen sein. Der vierte Operand ist eine Prozedur, die sowohl aus einem einzelnen Befehl als auch aus einem Block von Befehlen, der von { und } umschlossen wird, bestehen darf. Die vollständige Syntax dieses Befehls lautet Anfang Erhöhung Grenze Prozedur for. Wenn der Befehl ausgeführt wird, erzeugt PostScript eine vorübergehende Zählvariable (Steuervariable in der PostScript Terminologie) und setzt ihren Wert auf Anfang. Dieser Wert wird in den Operanden Stack eingefügt. Er kann auch von der Prozedur als Operand benutzt werden. Wenn er benutzt wird, wird er aus dem Operanden Stack entfernt, ansonsten bleibt er dort gespeichert. Nachdem die Zählvariable auf Anfabg gesetzt worden ist, wird die Prozedur ausgeführt. Danach wird die Zählvariable um den Wert von Erhöhung erhöht. Dieser Zyklus wiederholt sich dann auf diese Weise bis der Wert der erneut erhöhten Zählvariable den Wert von Grenze überschreitet. Überschreiten meint hier, aus dem Interval zwischen Anfang und Grenze zu fallen. Wenn Erhöhung positiv ist, dann ist die Ausführung mit for beendet, sobald die Zählvariable größer als Grenze wird. Ansonsten wird die forSchleife beendet, wenn die Zählvariable kleiner als Grenze wird. Der Abstand oder das Interval der Zählvariable darf nicht leer sein. Das bedeutet, daß Anfang kleiner sein muß als Grenze, wenn Erhöhung positiv ist und umgekehrt. Um dies noch deutlicher zu machen, hier das folgende Beispiel.

GS>1 -0.5 -1 {} for pstack
-1.0
-0.5
0.0
0.5
1.0
GS<5>clear 0 1 1 23 {add} for pstack
276
GS<1>

Der erste Befehl tut hier nichts, weil keine Prozedur vorhanden ist, sie ist null. Deshalb werden alle Werte der Zählvariablen im Operanden Stack gespeichert und verbleiben dort, da es keine Prozedur gibt, die ihre Werte braucht. Der zweite Befehl enthält jedoch eine add Prozedur, die zwei Operanden benötigt. Der erste Operand ist hier immer das oberste Element auf dem Operanden Stack und der zweite Operand ist der Wert der Zählvariablen der Schleife, der bei diesem Schritt in den Operanden Stack eingefügt wird. Der zweite Befehl berechnet die Summe der ersten 23 positiven Integer. Er benötigt einen Anfangswert für die Additionsprozedur. Dieser wurde vor dem Befehl als 0 angegeben. In anderen Worten heißt das, daß 0 kein Teil des for Befehls ist.

forall:Dieser Befehl führt die Prozedur für jedes Element eines gegebenen Feldes aus. Zu diesem Zweck zählt es jedes Element des gegebenen Feldes, beginnend mit null. Es benutzt eine vorübergehende Zählvariable zum Steuern der Schleife. Der Anfangswert der Zählvariablen ist 0, sein Increment ist 1 und seine Begrenzung ist die Länge des vorgegebenen Feldes. Das Schleifenschema ist fast genauso wie das für den for Befehl. Der einzige Unterschied ist die Verwendung von Feldelementen anstelle der Zählvariablen durch die Prozedur dieses Befehls. Der Befehl benötigt zwei Operanden, wobei der erste das Feld ist Der zweite Operand ist die Prozedur. Die vollständige Syntax von diesem Befehl lautet Feld Prozedur forall . Das folgende Beispiel, das die Summe eines vorgegebenen Feldes berechnet und alle Elemente eines anderen Feldes auf dem Operanden Stack ablegt, dient zur weiteren Erklärung dieses Befehls.

GS>0 [11 23 45 -89 26 12 0 -34] {add} forall pstack
-6
GS<1>[1 22 -12 0] {} forall pstack
0
-12
22
1
-6
GS<5>

loop:Dieser Befehl benötigt nur einen Operanden und das ist die Prozedur, die ausgeführt werden soll. Wenn benutzt, wiederholt er die Prozedur, ohne zu stoppen. In anderen Worten ist es eine endlose Schleife, die nur von außen, z.B. mit Ctrl-C abgebrochen werden kann, wenn die Prozedur nicht über eine spezielle Struktur verfügt. Wenn die auszuführende Prozedur irgendwo die Befehle exit oder stop stehen hat, dann wird die Schleife angehalten, wenn einer dieser beiden Befehle erreicht wurde, und die Steuerung kehrt zum nächsten Objekt im Interpreter zurück. Die Syntax für diesen Befehl lautet Prozedur loop.

Prozeduren oder Macro Definitionen

In PostScript bedeuten Prozedur oder Macro eine geordnete Menge von Objekten. Diese Objekte müssen sich innerhalb eines Paares von Blockabgrenzern, { und }, befinden. Sie können durch die Benutzung von Schlüsseldefinitionen /Macro1 {1 add 2 mul} def benannt werden. Wenn dies geschehen ist, dann wird /Macro zum Schlüssel und sein Wert {1 add 2 mul} wird zum aktuellen Verzeichnis, das sich im Verzeichnisstack befindet, als oberstes Element als ein Schlüssel-Wert Paar eingefügt. Wenn dann das Objekt Macro1 im Interpreter Prompt eingegeben wird, wird seine Aktion ausgeführt. Die Prozedur, die in dem Block definiert ist, kann so einfach oder kompliziert sein, wie du willst. In zukünftigen Artikeln werden wir auf macros noch weiter eingehen. Momentan reichen dieses einführenden Informationen für unseren Zweck aus.

Übungen

In diesem Artikel beginnen wir damit, dem Leser einige Aufgaben zu stellen. Die Antworten auf die Fragen werden wir dann im folgenden Artikel geben.

  1.   Schreibe eine Prozedur, die einen Integer als Operanden nimmt und die Summe der Quadrate des Integers zwischen 1 und diesem Operanden einschließlich berechnet.

  2.   Schreibe eine Prozedur, die zwei Integeroperanden nimmt und die Würfel des Integers zwischen dem ersten und zweiten Operanden einschließlich berechnet. Die Prozedur muß ein Feld erzeugen und die Würfel in das Feld als Elemente legen.

  3.   Schreibe eine Prozedur, die einen Feldoperanden nimmt und das arithmetische Mittel der Elemente im Feld berechnet. Es muß auch die Wurzel der Summe der Quadrate der Feldelemente berechnen.

  4.   Nimm an, in PostScript existierte keine exp Prozedur und schreibe eine Prozedur, die zwei numerische Werte als Operanden nimmt und den ersten als Basis und den zweiten als Exponent betrachtet. Die Prozedur berechnet die Macht des Exponenten zur Basis. Der Operand muß nach der Operation im Operanden Stack erhalten werden.

  5.   Das mathematische Objekt Matrix kann als ein Feld von Feldern angesehen werden. Eine N zeilige quadratische Matrix kann durch ein N-elementiges Feld dargestellt werden, dessen Elemente wiederum N-elementige Felder sind. Nenne diesen Typ von Feld aus Feldern "quadratische Matrix". Schreibe eine Prozedur, die einen Operanden der quadratischen Matrix nimmt und seine Spur (die Summe der diagonalen Elemente) berechnet. Das Ergebnis und die ursprüngliche quadratische Matrix müssen nach der Operation erhalten werden.

  6.   Schreibe eine Prozedur, die einen Operanden der quadratischen Matrix nimmt und ihre Transposition (die Zeilen werden mit den Spalten vertauscht) berechnet. Das Ergebnis und die ursprüngliche quadratische Matrix müssen nach der Operation erhalten werden.

  7.   Schreibe eine Prozedur, die zwei Operanden der quadratischen Matrix nimmt und ihre Matrixsumme berechnet. Das Ergebnis und die ursprüngliche quadratische Matrix müssen nach der Operation erhalten werden.

  8.   Schreibe eine Prozedur, die zwei Operanden der quadratischen Matrix nimmt und das Matrixprodukt von ihnen berechnet. Das Ergebnis und die ursprüngliche quadratische Matrix müssen nach der Operation erhalten werden.

Vom Englischen ins Deutsche übersetzt von Katja Korn