Stack-basierte Sprachen
Account:
Für die Übung erhalten Sie einen Account auf der
g0.complang.tuwien.ac.at. Sie können die den Übungsteil natürlich auch
zu Hause machen, und sich dafür Gforth
besorgen.
Bücher
Forth:
@Book{zech84,
author = "Ronald Zech",
title = "{Die Programmiersprache FORTH}",
publisher = "Franzis",
year = "1984",
address = "M{\"u}nchen",
edition = "First",
note = "In German"
}
@Book{woehr92,
author = "Jack Woehr",
title = "Forth: The New Model",
publisher = "M\&T Publishing/Prentice-Hall",
year = "1992"
}
@Book{kelly&spies86,
author = "Mahlon G. Kelly and Nicholas Spies",
title = "FORTH: A Text and a Reference",
publisher = "Prentice-Hall",
year = "1986",
note = "Available from Miller Microcomputer Services, 61
Lake Shore Road, Natick, MA, USA"
}
@Book{conklin&rather97,
author = {Edward K. Conklin and Elizabeth D. Rather},
title = {Forth Programmer's Handbook},
publisher = {Forth, Inc.},
year = {1997},
isbn = {0-9662156-0-5},
OPTannote = {}
}
Eher für Fortgeschrittene (wird oft auch empfohlen für Leute, die in
anderen Sprachen programmieren wollen):
@Book{brodie84,
author = {Leo Brodie},
title = {Thinking Forth},
publisher = {Fig Leaf Press (Forth Interest Group)},
year = 1984,
address = {100 Dolores St, Suite 183, Carmel, CA 93923, USA}
}
Postscript:
@Book{adobe99,
author = {Adobe Systems Incorporated},
title = {PostScript Language --- Reference Manual},
publisher = {Addison-Wesley},
year = 1999,
edition = {third},
url= {http://www.adobe.com/products/postscript/pdfs/PLRM.pdf}
}
Einführung:
@Book{adobe86blau,
author = {Adobe Systems Incorporated},
title = {PostScript Language --- Tutorial and Cookbook},
publisher = {Addison-Wesley},
year = 1988
}
Weiterführend:
@Book{adobe88gruen,
author = {Adobe Systems Incorporated},
title = {PostScript Language --- Program Design},
publisher = {Addison-Wesley},
year = 1988
}
------------------------------------
Forth
Systeme
Fuer diese LVA koennen Sie Gforth verwenden. Es ist auf der mips
installiert. Wer sich's zuhause installieren will, findet es unter
http://www.complang.tuwien.ac.at/forth/gforth/, inklusive binary
distributions fuer DOS, Windows, OS/2 und Linux.
Fuer Windows-programmierung hat Win32Forth einen guten Ruf (aber kaum
Doku). Es ist unter http://www.complang.tuwien.ac.at/forth/win32forth/
zu finden (und zwar das eigentliche Paket und das juengste
Update). Info gibt's unter
ftp://ftp.taygeta.com/pub/Forth/Compilers/native/windows/Win32For/
(W32for*.txt und W32for*.faq).
Dokumentation
Die Dokumentation von Gforth ist ueber Emacs-info (Ctrl-h i) oder
http://www.complang.tuwien.ac.at/forth/gforth/Docs-html/gforth_toc.html
zu lesen. Der Forth-Standard ist unter
http://www.complang.tuwien.ac.at/forth/dpans-html/dpans.htm zu finden.
Wer's nach Hause mitnehmen will, findet die Gforth-Doku in den Sourcen
bzw. die HTML-Version in
http://www.complang.tuwien.ac.at/forth/gforth/gf030htm.zip und den
Standard in http://www.complang.tuwien.ac.at/forth/dpans.zip.
Aus dem Skriptum für den Forth-Teil entstand das Gforth-Tutorial.
Die alte Version (in deutsch) ist auch noch verfügbar.
Später in der Vorlesung werden die Programme aus Bernd Paysans
One-Screener-Sammlung besprochen.
--------------------------------
Postscript
Systeme
Mit ein bißchen Aufwand kann man natürlich den Postscript-Interpreter
eines Postscript-Druckers benutzen. Einfacher und papiersparender ist
aber das Arbeiten mit Ghostscript. Man kann es direkt aufrufen mit
gs
und dann interaktiv damit arbeiten, was beim Lernen und Üben sehr
praktisch ist; für das Anzeigen von kompletten Postscript-Dateien ist
hingegen ghostview bequemer (besonders wenn die Dateien den Document
Structuring Conventions folgen).
Dokumentation
Dokumentation zu Ghostscript finden Sie in
/usr/local/lib/ghostscript/3.51/doc. Ein bißchen ist auch mit
man gs
und
gs -help
zu erfahren.
Syntax
Wie in Forth werden Lexeme von Leerzeichen getrennt. Neben den
Leerzeichen haben auch noch (, ), <, >, [, ], {, }, / und % spezielle
Syntaktische Eigenschaften: Es sind Delimiter; auch wenn sie von den
Lexemen vor und hinter ihnen nicht durch ein Leerzeichen getrennt
sind, sind sie einzelne Lexeme. Weiters sind auch noch << und >>
eigene Lexeme.
Mit % beginnen Kommentare, die bis zum Ende der Zeile reichen. Z.B.
%!PS-Adobe-3.0
%Das ist ein Kommentar
%%BoundingBox: 50 50 100 100
Strings werden von runden Klammern begrenzt. Runde Klammern innerhalb
von Strings muessen ausbalanciert sein, oder als \( bzw. \)
geschrieben werden. Z.B.
(string)
(string (mit balancierten Klammern))
(string \(nicht balanciert)
Namen (als Literale) beginnen mit /.
Datentypen
Postscript merkt sich die Typen von Objekten zur Laufzeit. Es weiß daher
immer, wie ein Objekt zu behandeln ist:
1 1 add pstack pop
1.0 1 add pstack pop
Es überprüft, ob die Operation zum Typ paßt:
(a) (b) add
Es gibt eine Menge Datentypen in PostScript. Sie lassen sich in
einfache (unteilbare) und zusammengesetzte einteilen.
Einfache Datentypen:
Typ Beispiel-Literal
integer 1
real 1.0
boolean true
name /name
mark [
null null
operator /add load
fontID
save
Die zusammengesetzten Datentypen in PostScript (Level 1) sind:
Typ Beispiel
array [1 2]
string (string)
dictionary << index1 wert1 index2 wert2 ... >> (PS Level 2)
File
Zusammengesetzte Daten werden durch eine Referenz repräsentiert, und
in vielen Operationen werden nur diese Referenzen verwendet, was zu
entsprechendem Verhalten bei Veränderungen und Vergleichen führt:
[1 2] [1 2] eq =
[1 2] dup eq =
Die beiden Arrays im ersten Beispiel werden durch verschiedenen
Referenzen repräsentiert, im zweiten Beispiel durch die gleiche.
Literale vs. ausführbare Objekte
Objekte haben nicht nur einen Typ, sondern auch das Attribut "literal"
oder "executable". Wenn ein literales Objekt ausgeführt wird, wird es
einfach auf den Stack geschoben. Wenn das gleiche Objekt dagegen
"executable" ist, wird es beim Ausführen ausgeführt (was verschiedene
Effekte haben kann).
So ist zum Beispiel
/add
die literale Form für den Namen "add",
add
ist dagegen seine ausführbare Form; wenn sie ausgeführt wird, führt
sie den zugehörigen eingebauten Operator aus.
Was macht ein ausführbares Objekt, wenn es ausgeführt wird (z.B. über
exec
oder die Ausführung eines Namens, an den das Objekt
gebunden ist)?
Name: führt das mit dem Namen im aktuellen Kontext assoziierte Objekt aus.
Operator: führt ein built-in aus.
Array: wenn der Interpreter das Array direkt erhält, wird es einfach auf
den Stack geschoben; wenn er es indirekt (über das Ausführen eines Namens)
ausführt, führt er die Elemente des Arrays aus.
Strings und Files: werden interpretiert.
null: tut gar nichts.
Wie schreibt man ausführbare Objekte hin?
Typ Beispiel-Executable Beispiel-Literal
Name name /name
Operator //add /add load
Array {dup mul} [ 1 2 ]
Ausführbare Arrays heißen auch Prozeduren.
Attribute
Neben der Ausführbarkeit haben Objekte noch das Access-Attribut, mit
dem der Zugriff eingeschränkt werden kann. Da Objekte normalerweise
unbeschänkten Zugriff erlauben, wird dieses Attribut hier nicht weiter
besprochen.
Wenn Objekte als Daten betrachtet werden (z.B. bei Vergleichen),
spielen die Attribute keine Rolle.
Prozeduren und Arrays
Die Syntax für Prozeduren ist:
{objekt1 objekt2 ...}
Dabei werden ausführbare Objekte nicht ausgeführt sondern als
ausführbare Objekte im Array gespeichert. Weiters führt der
Interpreter die Prozedur nicht aus, sondern schiebt sie auf den
Stack.
Literale Arrays werden so hingeschrieben:
[objekt1 objekt2 ...]
Dabei ist "[" nur das mark-Objekt:
[ ==
Die Objekte schieben sich selbst auf den Stack (wenn sie Literale
sind), und das abschliessende "]" räumt den Stack bis zum letzten mark
ab und baut aus den Elementen ein Array.
Namen und Dictionaries
Man kann Prozeduren mit einem Namen assoziieren:
/squared {dup mul} def
5 squared =
Dictionaries sind assoziative Arrays und assoziieren Objekte (meistens
Namen) mit anderen Objekten; sie entsprechen ungefaehr Forth's
wordlists. Es gibt einen Dictionary stack (entspricht der
search-order in Forth), der von oben nach unten durchsuicht wird, wenn
ein Name gesucht wird. "def" assoziiert das Paar im aktuellen
Dictionary (dem obersten im Stack).
Mit "load" kann man im Dictionary-stack nachschauen, welches Objekt
mit einem Namen (oder sonstigem Schlüsselobjekt) assoziiert ist:
/squared load ==
Binding
In Postscript werden in Prozeduren normalerweise Namen abgelegt, deren
Wert erst zur Ausführungszeit ermittelt wird.
/bar {foo} def
/foo {(hello, world) =} def
bar
Diese Late-Binding-Semantik ist einer der signifikantesten
Unterschiede zu Forth; sie erfordert ein sorgfältiges Management des
Dictionary-Stacks, um unangenehme Überraschungen zu vermeiden.
Außerdem wirkt sie sich nachteilig auf die Geschwindigkeit aus.
Mittels "bind" kann man wenigstens die Namen von Operatoren
(Built-ins) früh binden:
/myadd {add} bind def
/add {foo} def
1 2 myadd =
/myadd load ==
Mittels "//name" erhält man den Wert, der mit dem Namen im Moment
assoziiert ist:
//myadd ==
Und zwar funktioniert das, im Gegensatz zu "/name load", auch in
Prozeduren:
{//myadd} ==
Leider hat man damit auch noch kein richtiges early binding.
Das Late-Binding in Postscript wird natürlich auch als Feature
benutzt: So kann man sich lokale Variablen definieren, indem man ein
dictionary anlegt, und auf den dictionary stack legt, und dort die
lokalen Namen bindet und das Dictionary am Ende der Prozedur wegwirft.
Es werden auch Parameter übergeben, indem Dictionaries übergeben
werden.
Stacks
Postscript hat vier Stacks:
Operandenstack: Entspricht dem Daten- und Floating-Point Stack in Forth.
Dictionary Stack: Entspricht der search order in Forth. "begin"
schiebt ein Dictionary auf diesen Stack, "end" popt das oberste
Dictionary.
Execution Stack: Speichert die Rücksprungaddressen der gerade
ausgeführten Prozeduren. Entspricht dem Returnstack in den meisten
Forth-Implementationen, kann aber nicht zum Zwischenspeichern von
Daten benutzt werden.
Graphics State Stack: Speichert Graphik-Zustände. man kann den
aktuellen Graphics state mit gsave auf diesen stack schieben, oder mit
grestore einen graphics state von diesem Stack holen und ihn zum
aktuellen graphics state machen.
Kontrollstrukturen
In Postscript werden Kontrollstrukturen ueber Operatoren
implementiert, denen normalerweise Prozeduren als Parameter uebergeben
werden. Die Prozeduren werden ggf. ausgeführt.
true { 1 == } if
false { 1 == } if
true { 1 == } { 2 == } ifelse
5 1 10 { == } for
5 2 10 { == } for
[ 1 7 3 ] { == } forall
<< /c 1 /a 2 /b 3 >> { == == } forall
4 { (abc) = } repeat
5 { dup 0 lt { exit } if dup = 1 sub } loop pop
Graphik
Allgemeines Modell: Zuerst wird ein path auf gebaut (der als
impliziter Zustand vorhanden ist), der dann mit stroke (Linien
anzeigen), Fill (Flaechen fuellen), oder show (Zeichen anzeigen) auf
das Bild (die Bitmap) der Seite im Speicher gemalt wird. Die Seite
wird irgendwann mit showpage ausgegeben. Bei Ausgabe auf dem
Bildschirm zeigt ghostscript die Graphik sofort nach den Ausfuehren
von stroke, fill, oder show an.
Zum Erzeugen von Paths gibt es verschiedene Kommandos, die im
folgenden erklaert werden.
Linien und Flaechen
Alle Groessenangaben sind in Punkt (1/72 Zoll, ~0.35mm).
100 100 moveto
150 150 lineto
50 -50 rlineto %relativ
stroke
200 200 moveto
50 -50 rlineto
50 50 rlineto
closepath
stroke
100 100 moveto
150 150 lineto
50 -50 rlineto %relativ
fill
300 100 moveto
300 300 100 60 120 arc %andere varianten: arn arct arcto
stroke
100 400 moveto 100 500 200 500 200 400 curveto %bezier
stroke
100 400 moveto 200 500 100 500 200 400 curveto
stroke
Die Linienbreite kann man aendern:
5 setlinewidth
100 100 moveto
150 150 lineto
50 -50 rlineto %relativ
stroke
Ebenso die Arten, wie Ecken und Linienenden gezeichnet werden:
1 setlinecap %round; 0=butt, 2=projecting square
1 setlinejoin %round; 2=bevel; 0=miter (siehe auch setmiterlimit)
10 setlinewidth
100 100 moveto
150 150 lineto
50 -50 rlineto %relativ
stroke
Weiters kann man noch strichlierte Linien zeichnen
[2] 0 setdash
100 100 moveto 20 0 rlineto stroke
[2] 1 setdash
100 105 moveto 20 0 rlineto stroke
[2 1] 0 setdash
100 110 moveto 20 0 rlineto stroke
[2 1] 2 setdash
100 115 moveto 20 0 rlineto stroke
[2 1 3 2] 0 setdash
100 120 moveto 20 0 rlineto stroke
[] 0 setdash
100 125 moveto 20 0 rlineto stroke
Farben
0.7 setgray
5 setlinewidth
100 100 moveto
150 150 lineto
50 -50 rlineto %relativ
stroke
1 0 0 setrgbcolor %rot
3 setlinewidth
100 100 moveto
150 150 lineto
50 -50 rlineto %relativ
stroke
Zeichenketten
/Helvetica findfont 12 scalefont setfont
600 100 moveto
(ABC) show
(ABC) stringwidth == ==
Koordinatensysteme und Transformationen
2 0.5 scale
100 100 translate
90 rotate %Angaben in Grad
Transformationn wirken sich auf alle künftigen Angaben aus,
inkl. koenftige Transformationen:
2 2 scale 100 100 translate
ist etwas anderes als
100 100 translate 2 2 scale
Ein Postscript-File nach den Document Structuring Conventions: Source, Ergebnis.