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.

Beispiele für EPS-Graphiken