HomeMapIndexSearchNewsArchivesLinksAbout LF[Top Bar]
[BottomBar] 
 
[Photo of theAuthor] 
Emre Demiralp 

Über den Autor:
Ich bin Student am ?İstanbul American Robert College und gleichzeitig einer der Administratoren des Rechnerpools der wissenschaftlichen und literarischen Fakultät der Technischen Universität Istanbul. Linux ist hier das dominierende Betriebssytem. Meine Interessen: PovRay, PostScript, Animationen, CD Design, Programmierung, Holographie und vieles mehr. Seit 1994 beschäftige ich mich mit Linux.

M@il an den Autor 

Einleitung

Manipulation des Stapels

Mathematische Operatoren

Der PostScript Operandenstapel: Manipulatoren und mathematische Operatoren

-Der zweite Artikel der The PostScript Artikelserie-
[Ilustration] 
Tropfen für Tropfen entsteht ein See 
-Türkisches Sprichwort-.
Zusammenfassung:
Der Autor beschreibt den Operandenstapel der PostScript Sprache. Vorgestellt werden Manipulatoren und mathematische Operatoren. Dieser Artikel deckt wohl nicht alle Aspekte des Operandenstapels ab. In den nächsten Artikeln wird weiter auf ihn eingegangen.  
 
 


Einleitung

Dies ist der zweite Artikel der Reihe über PostScript. Hauptschwerpunkt in diesem Text liegt auf den Stapeloperationen. Der Operandenstapel ist möglicherweise das wichtigste Element von PostScript. Zuweisungen, arithmetische bzw. mathematische Operationen, Schleifen und logische Operationen werden alle über dieses besondere Stück Speicher verwaltet. Exakt, der Stapel ist ein besonderer Speicherbereich, der von PostScript beutzt wird, um alle möglichen PostScript Aktionen auszuführen. Der Stapel ist eine LIFO (Last In, First Out) Struktur, d.h. Daten, die zuletzt eintreffen, werden als erstes wieder entfernt/abgearbeitet. Man kann sich das ganze als Röhre vorstellen, von deren Enden eines verschlossen ist. Steckt man nun etwas in die Röhre hinein, so wird deren Inhalt in Richtung geschlossenes Ende geschoben und so Platz für den zusätzlichen Inhalt geschaffen. Gleichzeitig befindet sich der letzte Neuzugang am nächsten zu dem offenen Ende der Röhre hin.
Der Stapel akzeptiert verschiedene Elemente, wie Zeichenketten, numerische Konstanten, Schlüssel, Blöcke, uvm.

Manipulation des Stapels

Obwohl alle Elemente des Stapels geordnet sind, können diese durch entsprechende Stapeloperationen reorganisiert werden. Solche Stapelmanipulatoren werden immer auf ein oder mehrere Stapelelemente angewendet. Die Operatoren manipulieren, per definitionem, ein oder mehrere Elemente des Stapels. Manche erwarten Parameter ("Operanden" in der PostScript Terminologie), in Abhängigkeit der Manipulation. Werden Parameter benötigt, so müssen diese zuerst auf den Stapel gelegt werden. Der Operator führt dann mit den Parametern eine Aktion aus. Es folgt eine Liste von Operatoren mit ihren Funktionen. Danach werden einige Details anhand von Beispielen verdeutlicht.

pop: Dieser Operator entfernt das oberste Element (also das zu letzt abgelegte Element) des Operandenstapels.

exch: Es werden die beiden obersten Stapelelemente vertauscht.

dup: Es wird eine Kopie des obersten Elementes des Operandenstapels erzeugt und auf den Stapel gelegt, mit anderen Worten: das oberste Element wird dupliziert.

copy: Dieser Operator benötigt einen Operanden (Parameter) vom Typ integer, welcher auf den Stapel gelegt wird, bevor der Operator ausgeführt wird. Sei n der Integer Parameter, so sieht das Kommando wie folgt aus: n copy. Nach der Ausführung befinden sich Kopien der n obersten Stapelelemente an der Spitze des Stapels, d.h. copy ist ein Operator, der eine Menge von Elementen dupliziert.

index: Dieser Operator benötigt einen Operanden (Parameter) vom Typ integer, welcher auf den Stapel gelegt wird, bevor der Operator ausgeführt wird. Sei n der Integer Parameter, so sieht das Kommando wie folgt aus: n index. Nach der Ausführung befindet sich eine Kopie des n-ten Elementes von oben auf der Spitze des Stapels, d.h. index wählt ein beliebiges Stapelelement aus und erzeugt eine Kopie davon, welche dann auf den Stapel gelegt wird. Das oberste Stapelelement hat den Index 0.

roll: Dieser Operator benötigt zwei Operanden (Parameter) vom Typ integer, welche auf den Stapel gelegt werden, bevor der Operator ausgeführt wird. Es findet eine Verschiebung von Stapelelementen statt. Seien m und n diese beiden Integer Parameter, so sieht das Kommando wie folgt aus: m n index. m legt fest, wieviele Elemente verschoben werden, während n angibt, wie oft verschoben wird. Eine Verschiebung selbst sieht so aus: Das oberste Element des Stapels wird zum m-ten Element, während die m-1 Elemente, die dem ersten Element im Stapel folgten, jeweils um einen Platz nach oben rutschen. Diese Aktion findet also bei n gleich 1 statt. Für n größer 1 wird dies entsprechend oft mit dem jeweils gänderten Stapel wiederholt. Es ist also egal, ob man m 2 roll oder m 1 roll m 1 roll ausführt. n kann auch negativ sein. In diesem Fall würde die Aktion, die bei positiven n ausgeführt worden wäre, wieder aufgehoben werden. Der Effekt von m n roll m -n roll ist also, daß es gar keinen Effekt hat, der Stapel bleibt unverändert. Der Index des obersten Elementes ist 0.

clear: Dieser Operand verwirft alle Elemente des Stapels.

count: Dieser Operator zählt die Elemente eines Operandenstapels. Das Ergebnis wird als neues Element auf den Stapel gelegt. Falls dies nicht erwünscht ist, kann das folgende zusammengesetzte Kommando ausgeführt werden: count pstack pop. pop entfernt hierbei das neue Element, welches durch count erzeugt worden ist, nachdem das Ergebnis des Zählens durch den Dateioperator pstack angezeigt worden ist.

mark: Dieser Operator legt das Element -marktype- auf den Stapel. Durch dieses Element kann die Menge der Stapelelemente in Teilmengen gegliedert werden. Zwei weitere Operatoren, cleartomark und counttomark benutzen dieses Element für ihre Aktionen. Sollte keines gefunden werden, wird eine Fehlermeldung ausgegeben.

cleartomark: Durch diesen Operator werden alle Elemente vom Anfang des Stapels bis zum ersten -marktype- Element verworfen. -marktype- wird ebenfalls verworfen. Falls kein Objket vom Typ Marktype auf dem Stapel gefunden wird, wird eine Fehlermeldung ausgegeben.

counttomark: Alle Elemente, angefangen vom obersten Element, bis hin zum ersten Marktype Objekt werden gezäht. Das Ergebnis wird als oberstes Element auf den Stapel gelegt. Das Marktype Element selbst wird nicht mitgezählt. Sollte kein solches Objekt im Stapel zu finden sein, beschwert sich PostScript und es findet keine Aktion statt.

Nun ein paar Worte zum Stapel. Bevor obige Operatoren benutzt werden können, muß der PostScript Interpreter aktiviert werden. Wie im ersten Artikel schon erwähnt wurde, findet der frei erhältliche Interpreter ghostscript in der Linux Gemeinde Anwendung. Ghostscript kann auf verschiedene Weise, mittels den entsprechenden Parametern, aktiviert werden. Normalerweise wird er einfach via gs unter X aufgerufen. Auf Grund von Problemen bei der Konfiguration kann dies scheitern, es wird eine Fehlermeldung ausgegeben, die einem mitteilt, daß keine passende Grafikkonsole erzeugt werden konnte. In diesem Fall versucht man entweder, das Problem zu beheben, oder zwingt ghostscript dazu, das Gerät (device) x11 zu benutzen. Dafür sieht der Aufruf von Ghostscipt wie folgt aus: gs -sDEVICE=x11. Dadurch (oder falls ein einfaches gs auch funktioniert) wird ein leeres Fenster mit weißem Hintergrund geöffnet, welches Ghostscript während der Ausführung für eventuelle Darstellungen benutzt. Da in diesem Artikel nichts dargestellt wird, ist dieses Fenster recht sinnlos. Man kann Ghostscript mittels dem zusätzlichen Parameter -dNODISPLAY dazu bringen, ohne dieses Fenster zu starten. Wird so der Interpreter gestartet, so wird eine Copyright Nachricht angezeigt, gefolgt von der Ghostscript Eingabeaufforderung GS> am Anfang einer neuen Zeile. Ab jetzt wartet Ghostscript auf die Eingabe von Kommandos. Der Operandenstapel ist leer.

Durch den Dateioperator pstack kann der Inhalt des Operandenstapels angezeigt werden. Der Operator heißt Dateioperator, da er Informationen über den Stapelinhalt an die Datei der Standardausgabe, im Normalfall der Bildschirm, sendet. Wird dieses Kommando jetzt eingegeben, so wird nichts angezeigt, ein neuer Eingabeprompt GS> erscheint am Anfang einer neuen Zeile. Dadurch wird angedeutet, daß der Stapel leer ist.

Elemente, die auf den Stapel gelegt werden sollen, werden einfach an der Eingabeaufforderung eingeben. Um zum Beispiel den Wert 1 auf den Stapel zu legen, wird einfach 1 eingegeben. Danach wird wieder ein Prompt in einer neuen Zeile dargestellt. Allerdings wird diesmal nicht GS> als Prompt angezeigt, sondern GS<1>. Dieser neue Prompt spiegelt immer die momentane Anzahl von Stapelelementen wieder. Der Prompt GS<123> gibt also an, daß zum gegenwärtigen Zeitpunkt 123 Elemente auf dem Stapel liegen.

Es können auch mehrere Elemente auf einmal auf den Stapel gelegt werden. Dies geschieht, indem man nacheinander, durch Leerzeichen getrennt, die Elemente eingibt. Zum Beispiel werden durch Eingabe von 1 2 3 4 5 6 am Prompt, die Elemente 1, 2, 3, 4, 5, 6 nacheinander auf den Stapel gelegt. Durch die Ausführung von pstack nach der Eingabe, werden die Elemente in vertikaler Anordnung angezeigt. Dabei wird das zuletzt eingegebene Element als Erstes angezeigt. Die Ausgabe dieser beiden Kommandos sieht wie folgt aus:

GS>1 2 3 4 5 6 
GS<6>pstack
6
5
4
3
2
1
GS<6>
Es ist auch möglich, die Eingabe der Elemente und die Anzeige des Stapelinhaltes in einem einzigen Schritt durchzuführen. Dazu muß nur das Kommando pstack hinter den Elementen eingegeben werden:
GS>1 2 3 4 5 6 pstack
6
5
4
3
2
1
GS<6>
Bisher wurden nur Zahlen als Elemente verwendet. Aber nicht nur Zahlen, auch andere Elemente, wie Variablen, Zeichenketten und Blöcke können eingegeben werden. Dies wird später noch detailierter gezeigt. Es sollte jedoch jetzt schon erwähnt werden, daß bei dem Versuch, zum Beispiel ein einzelnes Zeichen a oder eine Zeichenkette abc einzugeben, eine Fehlermeldung ausgegeben wird. Dies geschieht, da PostScript so nicht mit diesen Elementen umgehen kann. Um ein einzelnes Zeichen oder einen String einzugeben, muß die Eingabe geklammert werden, mit ().
Ein spezieller Elementetyp namens Marktype wurde schon vorgestellt. Hier ein Beispiel:
GS>1 2 3 mark 4 5 6 pstack
6
5
4
-marktype-
3
2
1
GS<7>
Nun werden einige Operatoren für die Manipulation des Operandenstapels und deren Wirkungsweisen anhand von Beispielen gezeigt. Damit wird dieser Abschnitt ohne weitere Erklärungen abgeschlossen.
GS>1 2 3 mark 4 5 6 pstack
6
5
4
-marktype-
3
2
1
GS<7>pop pstack
5
4
-marktype
3 
2
1
GS<6>exch pstack
4
5
-marktype
3
2
1
GS<6>dup pstack
4
4
5
-marktype-
3
2
1
GS<7>2 copy pstack
4
4
4
4
5
-marktype
3
2
1
GS<9>5 index pstack
-marktype-
4
4
4
4
5
-marktype
3
2
1
GS<10>cleartomark cleartomark pstack
3
2
1
GS<3>3 1 roll pstack
2
1
3
GS<3>count pstack
3
2
1
3
GS<4>mark 7 8 pstack
8
7
-marktype-
3
2
1
3
GS<7>counttomark pstack
2
8
7
-marktype-
3
2
1
3
GS<8>clear pstack
GS>

Mathematische Operatoren

Neben den Operatoren für die Manipulation des Operandenstapels gibt es noch einige arithmetische und mathematische Operatoren. Diese werden weiter unten vorgestellt. Es bleibt hier dem Leser überlassen, mit den Operatoren zu experimentieren. Der vorhergehende Abschnitt sollte gezeigt haben, wie man mit dem Interpreter arbeitet.

add: Dieses Kommando erwartet zwei numerische Parameter. Seien diese Werte m und n, so sieht das Kommando wie folgt aus: m n add. Dadurch wird zuerst m, dann n auf den Stapel gelegt. Im letzten Schritt wird der add Operator auf die beiden obersten Elemente des Stapels angewandt und das Ergebnis, welches die Summe von m und n ist, als neues Element auf den Stapel gelegt. Nach Beendigung der Operation werden m und n nicht weiter auf dem Stapel gehalten, das Ergebnis wird das oberste Stapelelement.

div: Zwei Parameter erwartet dieses Kommando, deren Werte in die Division einfließen. Seien diese Werte m und n dann sieht das Kommando so aus: m n div. Die Operation verläuft ähnlich dem add Kommando ab, m wird durch n geteilt. Die Division findet im Fließkommabereich statt. Das Ergebnis verbleibt als oberstes Element im Stapel, m und n werden verworfen.

idiv: Identisch zum div Operator, außer, daß die Operation auf Integerebene (also ganzzahlig) stattfindet. Funktioniert auch, falls die Parameter keine Integerwerte sind.

mod: Das Kommando erwartet zwei Integer Parameter. Es ermittelt den Rest der Division des ersten Parameters durch den zweiten. Sollte einer der Parameter kein Integer sein, scheitert das Kommando. Das Ergebnis verbleibt nach der Operation auf dem Stapel, die Parameter werden verworfen.

mul: Ähnlich den Kommandos add und div. mul ist ein binärer Operator, erwartet zwei numerische Werte. Das Ergebnis der Multiplikation verbleibt auf dem Stapel.

sub: Wie add, div und mul. Das Kommando unterscheidet sich allerdings vom Operationstyp. Der Wert des zweiten Parameters wird vom Wert des ersten abgezogen. Parameter und Ergebnis sind numerische Werte. Das Ergebnis wird auf dem Stapel gehalten.

exp: Ein binärer mathematischer Operator, der zwei Parameter erwartet. Der erste Wert ist die Basis, der zweite der Exponent. Das Kommando potenziert die Basis abhängig vom Exponenten. Die Parameter müssen innerhalb des Bereiches für die Exponentialoperation liegen. Das Ergebnis, welches eine Fließkommazahl ist, wird als neues Element auf den Stapel gelegt.

atan: Ein weiterer binärer Operator für die Berechnung eines Winkels. Der Winkel liegt zwischen 0 und 360. Der Operator erwartet zwei Parameter. Das Verhältnis des ersten Parameters zu dem zweiten entspricht dem Tangens des zu berechnenden Winkels. Einer der beiden Werte kann Null sein, jedoch nicht beide. Die Vorzeichen der Parameter bestimmen den Quadranten, in dem das Ergebnis liegen wird. Ein positiver Wert des ersten Parameters entspricht dabei der positiven Y Ebene, ein positiver zweiter Wert der positiven X Ebene.

abs: Dies ist ein unärer Operator. Er erwartet einen Parameter und gibt den Absolutwert zurück. Wie bei den vorigen Operatoren liegt das Ergebnis als neues Element auf dem Stapel.

neg: Ein unärer Operator, der das Vorzeichen des einzigen Argumentes umkehrt.

ceiling: Durch diesen unären Operator wird der dem Argument nächst höhere Integerwert berechnet.

floor: Durch diesen unären Operator wird der dem Argument nächst niedrigere Integerwert berechnet.

round: Dieser unäre Operator berechnet den dem Argument am nahesten liegenden Integerwert.

truncate: Der unäre Operator schneidet den Nachkommaanteil des Argumentes ab.

sqrt: Dieser unäre Operator berechnet die Quadratwurzel des Argumentes.

cos: Berechnung des Cosinus des Argumentes. Das Argument ist ein Winkel, in Grad angegeben.

sin: Berechnung des Sinus des Argumentes. Das Argument ist ein Winkel, in Grad angegeben.

ln: Berechnet den Logarithmus Naturalis des Argumentes.

log: Berechnet den Zehner-Logarithmus des Argumentes.

Eine Bemerkung: Die Parameter (in der Terminologie von PostScript: Operanden) eines Kommandos können einige Probleme verursachen. Das Kommando (Operator) erwartet seine Parameter auf dem Operandenstapel. Es kann so unfreiwillig oder ausversehen dazu kommen, daß ein Kommando, welches Parameter erwartet, auf den Stapel gelegt wird, ohne daß die richtigen Parameter vorher draufgelegen haben. Entweder wird der Intepreter sich über fehlende/falsche Parameter beschweren oder es werden die oberen Elemente fälschlich entfernt. Der Benutzer muß also mit Bedacht vorgehen.

Abschließend wird dem Leser, der sich weiter mit PostScript beschäftigen möchte, geraten, komplexere und ausdruckstärkere Programme zu schreiben. Die nachfolgenden Artikel dieser Serie beschäftigen sich detailierter mit einigen Aspekten der PostScript Sprache. Fragen und Anregungen sind dabei willkommen.


Übersetzung: Harald Radke
This website is maintained by Miguel Angel Sepulveda 
© Emre Demiralp 1999 
LinuxFocus 1999