Tcl
aus Wikipedia, der freien Enzyklopädie
Tcl (ursprünglich "Tool command language", also etwa "Werkzeugbefehlssprache") ist eine Open Source-Skriptsprache, die einfach zu erlernen ist und mit der Applikationen innerhalb kurzer Zeit erstellt werden können. Tcl wird üblicherweise wie tickle (engl., kitzeln) ausgesprochen oder auf deutsch Te Ce El. Sie ist mit Unix-Shell-Sprachen verwandt. Die Syntax sieht C-ähnlich aus, aber auch starke Bezüge zu Lisp sind vorhanden.
Der Wahlspruch von Tcl lautet "radically simple", also "radikal einfach", was sich auf die besonders simple, wenn auch etwas ungewöhnliche Syntax der Sprache bezieht.
Bekannt ist Tcl durch das Toolkit Tk, mit dem sich portable grafische Benutzeroberflächen leicht programmieren lassen. Der grafische Werkzeugkasten "Tk" steht für eine Vielzahl von Betriebssystemen mit dem für das System üblichen Aussehen ("native look and feel") zur Verfügung. Diese Programmierschnittstelle wird auch von Perl, Php, Ruby und Python benutzt. Die Kombination aus Sprache und Toolkit, auch bekannt als Tcl/Tk, ist jedoch besonders einfach zu verwenden; sie stammt von John Ousterhout (seit 1988). Tcl arbeitet standardmäßig mit Unicode, so dass Zeichenketten ohne besonderen Aufwand alle Zeichen bis U+FFFD enthalten können. Über 16 Bit hinausgehende Unicodes werden noch nicht unterstützt.
Inhaltsverzeichnis |
[Bearbeiten] Eigenschaften und Besonderheiten
- Alles ist ein String, inklusive der Kontrollstrukturen. Alle Befehle verwenden die Polnische Notation.
- Befehle und Variablen können dynamisch neu definiert oder überladen werden.
- Alle Datentypen können als Zeichenkette bearbeitet werden, auch Programmcode.
- Extrem einfache Syntax-Regeln.
- Ereignisgesteuerte Schnittstellen zu Sockets und Dateien. Zeit- und Benutzer-definierte Ereignisse sind ebenfalls möglich.
- Variablen-Scope auf lokale Variablen begrenzt, kann aber mit uplevel und upvar gezielt auf den Scope der aufrufenden Funktion erweitert werden.
- Einfache Ausnahmebehandlung durch Ausnahme-Rückgabewerte aller Befehle.
- Einfache Erweiterbarkeit in C, C++, Java und Tcl.
- Als Interpretierte Sprache erlaubt Tcl die Erstellung und Modifikation des laufenden Programms durch sich selbst, ist aber durch dynamische Übersetzung in Bytecode trotzdem schnell.
- Vollständige Unterstützung von Unicode 3.1 (seit 1999).
- Plattform-unabhängig: Win32, UNIX, Linux, Mac, usw.
- Enge Integration mit dem GUI-Toolkit Tk
- Einfach zu wartender Code. Tcl-Skripte sind häufig kompakter und besser lesbar als vergleichbarer Code in anderen Programmiersprachen.
- Kann in vielen Situationen und Umgebungen eingesetzt werden: als text-basierte Skriptsprache, als Basis für Programme mit graphischer Oberfläche, als Makrosprache innerhalb einer Applikation, als Sprache für dynamische Websites oder für Stored Procedures in Postgres.
- Steht in vielen Formen zur Verfügung: als BSD-lizenzierter Quelltext, als selbst-ausführendes Paket oder als kommerziell unterstütze Plattform (ActiveState Tcl).
[Bearbeiten] Syntax
Tcl ist im Grundsatz sehr einfach aufgebaut und grenzt sich gegen Sprachen wie Perl, APL und C durch absolut konsequenten Einsatz einer einheitlichen Syntax ab. Wer mit Kommandozeileninterpretern (Shell, MS-DOS) vertraut ist, kennt auch die Grundstruktur von Tcl-Kommandos. Ein Tcl-Skript besteht aus mehreren Kommandos. Ein Kommando besteht aus einem Kommandowort gefolgt von Argumenten (Parameter). Ein Kommando wird von einem Zeilenende oder Semikolon begrenzt. Gegenüber einfachen Kommandozeileninterpretern verfügt aber Tcl über die Möglichkeit, Kommandos ineinander zu verschachteln. Statt eines Argumentes in einem Kommando kann in eckigen Klammern ein weiteres Kommando angegeben werden. Die Unterkommandos werden zuerst ausgeführt. Ihr Resultat wird dann jeweils als Argument im übergeordneten Kommando eingesetzt. Der Mechanismus ist wie der der Backquotes bei der Unix-Shell.
Auch Konstrukte wie if und while, über Zuweisungen bis hin zu Kommentaren sind Kommandos. Der Kommentar ist ein Kommando, das einfach nichts tut. Die Kommandos folgen der Polnischen Notation, wie Lisp. Das Kommandowort steht am Anfang, dann folgen die Parameter.
kommandoWort par1 par2 ... parN
Ein umgekehrter Schrägstrich "\" (englisch Backslash) am Ende einer Zeile markiert, dass ein Kommando auf der nächsten Zeile fortgesetzt wird. Anführungsstriche schließen Zeichenketten ein. Damit keine Verwechslungen auftreten, sind einfache Anführungszeichen (Hochkommata) unbekannt. Auch das einfache Gleichheitszeichen (=) kommt nicht vor. Das doppelte Gleichheitszeichen dient Vergleichen.
Geschweifte Klammern schützen ihren Inhalt vor Interpretation. Dadurch können Kommandos dann auch mehrere (auch viele) Zeilen umfassen. Als Beispiel sei das While-Kommando erwähnt. Es erwartet zwei Argumente, das erste enthält einen Befehl, der die Bedingung repräsentiert, das zweite die auszuführenden Kommandos innerhalb der While-Schleife.
while { Bedingung } { FolgeVonTclKommandos }
Die geschweiften Klammern schützen den Inhalt vor der Interpretation *vor* dessen Übergabe an den While-Befehl. Innerhalb des While-Befehls werden sie so wie nötig evaluiert.
if { Bedingung } { FolgeVonTclKommandos }
oder
if { Bedingung } { FolgeVonTclKommandos } else { AlternativeFolgeVonTclKommandos }
oder
if { Bedingung } { FolgeVonTclKommandos } elseif { Bedingung } { FolgeVonTclKommandos } else { AlternativeFolgeVonTclKommandos }
Es können beliebig viele elseif-Anweisungen folgen.
Zuweisungen geschehen mit dem Kommando set – ohne ein Gleichheitszeichen. So ist auch hier kein Bruch in der extrem einfachen Syntax vorhanden:
set variable value
Weiter gibt es ein leistungsfähiges switch-Kommando, ein For- und ein Foreach-Kommando. Vor allem letzteres ist deutlich mächtiger als Iterationen in anderen Sprachen. Beispiel, um aus einer Liste von x/y-Koordinaten und einer weiteren aus z-Koordinaten eine Liste aus x/y/z-Koordinaten zu erstellen:
set xyzlist {} foreach {x y} $xylist z $zlist {lappend xyzlist [list $x $y $z]}
Es können also mehr als ein Element aus einer Liste, sowie Elemente aus mehreren Listen in einem Schleifendurchlauf verwendet werden.
Ein Kommando liefert einen Stringwert oder eine Liste als Resultat zurück.
glob aPattern
erzeugt eine Liste der Dateinamen im Arbeitsverzeichnis, deren Namen mit aPattern übereinstimmen. Pattern können ? (ein beliebiges Zeichen), * (0 oder mehr beliebige Zeichen) oder Klassen von Zeichen in eckigen Klammern enthalten. Dann aber sind letztere mit geschweiften Klammern vor zu früher Auswertung zu schützen:
glob {[abc]?-*.tcl}
liefert Datei- oder Verzeichnisnamen, die mit a, b oder c beginnen, danach aus einem beliebigen Zeichen und einem Bindestrich, danach einer beliebigen (auch leeren) Zeichenfolge und schließlich ".tcl" bestehen. Für dieses Kommando wird die Unix-Bibliotheksfunktion glob() verwendet.
Arithmetische Ausdrücke werden durch das Kommando expr ausgeführt.
set res [expr 4 + 2 * 3] puts $res
ergibt 10. Die Dynamik der Datentypen erlaubt einfache Codierung wie diese:
proc Quersumme Zahl {expr [join [split $Zahl ""] +]}
[split $Zahl ""]
zerlegt die Zahl in Ziffern, indem an jedem Leerstring (welcher zwischen allen Zeichen existiert) getrennt wird: 4711 wird zu 4 7 1 1[join ... +]
fügt zwischen je zwei Ziffern ein "+"-Zeichen ein[expr ...]
berechnet schließlich den so entstandenen Ausdruck.
[Bearbeiten] Datentypen
Tcl ist eine (nach außen hin) typlose Sprache. Jede Variable hat eine Zeichenkette als Wert. Dazu kann eine interne Repräsentation z. B. einer Ganzzahl, Fließkommazahl oder Liste treten. Die Verwendung einer nicht definierten Variable führt zu einem Fehler - im Gegensatz zur Programmierung mit dem Unix-Kommandozeileninterpreter (Shell) oder awk. Konstrukte wie assoziative Arrays (Hashtabelle) und Listen werden in Tcl oft angewendet.
Das folgende Programmschnipsel deklariert implizit einen assoziativen Array und füllt ihn mit Werten.
set hauptstadt(Frankreich) Paris set hauptstadt(Italien) Rom set hauptstadt(Deutschland) Berlin set hauptstadt(Polen) Warschau set hauptstadt(Russland) Moskau set hauptstadt(Spanien) Madrid
Alternativ ist folgende Schreibweise möglich, und oft kompakter:
array set hauptstadt { Frankreich Paris Italien Rom Deutschland Berlin .. .. }
Ein bestimmter Wert kann wie folgt auf das Ausgabemedium geschrieben werden
puts $hauptstadt(Italien)
Eine Liste von allen Ländern zu denen Hauptstädte angegeben worden sind, erzeugt der folgende Tcl-Befehl
array names hauptstadt
Der Tcl-Interpreter antwortet mit z. B.
Polen Spanien Russland Deutschland Italien Frankreich
Die Liste ist nicht sortiert. Die Liste wird sortiert ausgegeben mit:
lsort [array names hauptstadt]
[Bearbeiten] Bearbeitung von Zeichenketten
Tcl kennt sehr leistungsfähige Kommandos zur Bearbeitung von (auch langen) Zeichenketten – mindestens ebenbürtig denen von Perl und Python, ebenso Dateibearbeitung, TCP/IP-Netzkommunikation und über Tk grafische Programmierung und ist in all diesem völlig plattformunabhängig. Tcl hat einen Mechanismus eingebaut, um mit Regulären Ausdrücken arbeiten zu können, wobei auch komplexere Ausdrücke als die von grep unterstützt werden, vergleichbar mit denen von Perl.
[Bearbeiten] Einsatzbereiche
Tcl wird nicht nur auf der Kommandozeile, sondern auch als eingebettete Sprache (embedded language), als CGI-Sprache (wie sonst oft Perl) und als Modul im Apache-Webserver (wie sonst oft PHP) und als Sprache für Prozeduren in der Datenbank PostgreSQL eingesetzt. Sie ist über eine einfache Schnittstelle zu C leicht erweiterbar. Tcl kann als prozedurale ebenso wie als funktionale Programmiersprache eingesetzt werden, da Namen von Funktionen auch Argumente von Funktionen sein können. Über Erweiterungen wie stooop, Incr Tcl und Incr Tk sowie XOTcl ist Tcl auch objektorientiert – bis hin zur Mehrfachvererbung.
[Bearbeiten] Beispielprogramme
[Bearbeiten] Mittelwert einer Liste von Zahlen
proc mean data {expr ([join $data +])/double([llength $data])}
Die Funktion double() bewirkt, dass keine Integerdivision mit Abrundung, sondern eine Fließkomma-Division durchgeführt wird (das ist bei Mittelwerten in der Regel beabsichtigt).
[Bearbeiten] Spiegeln einer Liste
proc lrevert list { set res {} for {set i [llength $list]} {$i>0} {} { lappend res [lindex $list [incr i -1]] } set res }
Hier wird ein typisches Muster verwendet: Ergebnis auf leere Liste {} initialisieren – über die Eingabe iterieren, Ergebnis aufbauen – am Ende Ergebnis abgeben (statt set res hätte man auch return $res schreiben können, was sogar deutlicher wäre). Test:
% lrevert {a b c d} d c b a
[Bearbeiten] Umlautersetzung
proc noumlaut string { string map {ä ae ö oe ü ue ß ss Ä AE Ö OE Ü UE} $string }
Die Abbildungsliste (map) enthält jeweils abwechselnd die Zeichenketten, von und nach denen abgebildet werden soll. Das Beispiel zeigt ferner, dass es keine reservierten Wörter gibt – "string" ist sowohl Name des einzigen Kommandos als auch des einzigen Arguments.
[Bearbeiten] Fakultät
proc ! x {expr {$x<2? 1: $x*[! [incr x -1]]}}
Dies ist ein Beispiel für sehr kompakten, funktionalen Programmierstil. Es zeigt, dass beliebige Strings (hier "!") Namen von Funktionen sein können; dass innerhalb des expr-Kommandos auch der ternäre x?y:z-Operator wie aus C bekannt verfügbar ist; dass aber Tcl-Funktionen durchaus ganz anders als C-Programme aussehen können.
Variablennamen können auch Umlaute enthalten. Sogar Leerzeichen sind möglich, aber etwas unhandlich, weshalb davon abzuraten ist. Will man mit $name auf eine Variable zugreifen, so muss der Name aus A-Za-z0-9_ bestehen – mit ${name} hat man dagegen volle Freiheit im Zeichensatz.
Ein anderer Ansatz zur Fakultät benutzt Techniken der Funktionalen Programmierung. Zunächst die "Faltung":
proc fold {res op list} { foreach e $list {set res [$op $res $e]} set res }
Um sie als Funktionsnamen nutzen zu können, werden einige Operatoren aus dem expr-Kommando "exportiert":
foreach op {+ - * /} {proc $op {a b} "expr {\$a $op \$b}"}
Mit einem Alias kann man Funktionen mit Teilen ihrer Argumentliste versorgen (Currying):
interp alias {} product {} fold 1 *
Eine klassische Technik ist die funktionale Komposition:
proc o {f g x} {$f [$g $x]}
Schließlich ein Integer-Listengenerator, wie aus APL bekannt ([iota1 5] ==> {1 2 3 4 5}):
proc iota1 n { set res {} for {set i 1} {$i<=$n} {incr i} {lappend res $i} set res }
Und mit diesen allgemein verwendbaren Bausteinen kann man die Fakultät aus Produkt und Integervektor "komponieren":
interp alias {} ! {} o product iota1
[Bearbeiten] Schnittmenge
Unter der realistischen Annahme, dass Mengen als Listen repräsentiert sind, kann ein klassischer Filter verwendet werden - er gibt die Elemente einer Liste, die eine bestimmte Bedingung erfüllen, zurück:
proc filter {list script} { set res {} foreach e $list {if {[uplevel 1 $script $e]} {lappend res $e}} set res }
Kurzform für Enthaltensein eines Elements in einer Liste:
proc in {list e} {expr {[lsearch -exact $list $e]>=0}}
Die Schnittmenge zweier Mengen kann damit knapp definiert werden als
proc intersection {a b} {filter $a {in $b}}
Aufrufbeispiel:
% intersection {a b c} {b c d} b c
[Bearbeiten] Digitaluhr
Hier ein kleines Beispielprogramm in Tcl/Tk, eine Digitaluhr in 3 Zeilen (Quelle: The Tcl'ers wiki - A simple A/D clock):
proc every {ms body} {eval $body; after $ms [info level 0]} pack [label .clock -textvar time] every 1000 {set ::time [clock format [clock sec] -format %H:%M:%S]}
In der ersten Zeile wird ein Zeitgeber(Timer) angelegt, der ein Skript "body" regelmäßig alle "ms" Millisekunden ausführt (indem er sich selbst zum Wiederaufruf vormerken lässt). In der zweiten Zeile wird ein Label in einem Fenster auf dem Bildschirm angelegt und mit einer Variablen "time" verbunden. In der dritten Zeile wird der Timer "every" aufgerufen, um jede Sekunde die Variable "time" auf die aktuelle Uhrzeit im Format Stunde-Minute-Sekunde zu setzen. Fertig ist ein komplettes Programm mit GUI.
Das Kommando info level 0 gibt zurück, wie die aktuelle Prozedur aufgerufen wurde.
[Bearbeiten] Arraydaten abfragen
Im Array tcl_platform liegen Angaben zur Plattform vor, auf der der Tcl-Interpreter läuft. Das folgende Code-Stück gibt sie auf dem Standard-Ausgabemedium aus:
foreach i [array names tcl_platform] { puts [concat $i= $tcl_platform($i)] }
Eine hübschere Variante (alphabetisch sortiert, bündige Gleichheitszeichen) ist
parray tcl_platform
[Bearbeiten] Minimaler Editor
Der folgende Code definiert einen kompletten minimalen Editor; er stammt von Richard Suchenwirth [1]; detaillierte Erklärungen unter [2]
# Hilfetext definieren set about "minEd - a minimal editor Richard Suchenwirth 2003 F1: help F2: load F3: save " # GUI definieren, drei F-Tasten rufen Prozeduren auf pack [scrollbar .y -command ".t yview"] -side right -fill y pack [text .t -wrap word -yscrollc ".y set"] -side right -fill both -expand 1 bind . <F1> {tk_messageBox -message $about} bind . <F2> {loadText .t [tk_getOpenFile]} bind . <F3> {saveText .t [tk_getSaveFile]} proc loadText {w fn} { if {$fn==""} return wm title . [file tail $fn] set fp [open $fn] $w delete 1.0 end $w insert end [read $fp] close $fp } proc saveText {w fn} { if {$fn==""} return set fp [open $fn w] puts -nonewline $fp [$w get 1.0 "end - 1 c"] close $fp } # Falls Editor mit Angabe einer Datei aufgerufen wurde, diese öffnen. if {$argc > 0} {loadText .t [lindex $argv 0]}
[Bearbeiten] HTML-Seite herunterladen
Das http-Package enthält Befehle, um mit dem http-Protokoll zu arbeiten. Die folgenden Codezeilen laden eine HTML-Seite herunter.
package require http puts [http::data [set token [http::geturl http://mini.net/tcl/540]]] http::cleanup $token
[Bearbeiten] Erweiterung XOTcl
XOTcl ist eine objektorientierte Erweiterung von vielen, die es für Tcl gibt. Sie unterstützt auch Metaklassen. Definitionen von Klassen und Methoden sind vollständig dynamisch änderbar.
Auch ohne Erweiterungen können einige Konzepte objektorientierter Programmierung in Tcl ohne allzu großen Aufwand implementiert werden, da Funktionen wie Namensräume und Aliasse im Standard enthalten sind. Hier ein Beispiel für eine Stapel-"Klasse" mit den Methoden "push" und "pop":
namespace eval Stack {set n 0} proc Stack::Stack {} { #-- Konstruktor variable n set instance [namespace current]::[incr n] namespace eval $instance {variable s {}} interp alias {} $instance {} ::Stack::do $instance } proc Stack::do {self method args} { #-- Dispatcher mit Methoden upvar #0 ${self}::s s switch -- $method { push {eval lappend s $args} pop { if ![llength $s] {error "stack underflow"} set top [lindex $s end] set s [lrange $s 0 end-1] set top } default {error "unknown method $method"} } }
Die "pop"-Methode ist etwas länglich. Mit dem schlichten K-Kombinator
proc K {a b} {set a}
(etwa wie PROG1 in Lisp) lässt sie sich vereinfachen zu
pop { if ![llength $s] {error "stack underflow"} K [lindex $s end] [set s [lrange $s 0 end-1]] }
Test mit einer interaktiven Tcl-Shell:
% set s [Stack::Stack] ;#-- Konstruktor ::Stack::1 ;#-- generierter Name des Stapels % $s push hello hello % $s push world hello world % $s pop world % $s pop hello % $s pop stack underflow ;#-- Fehlermeldung, weil Stapel leer % namespace delete $s ;#-- Destruktor
[Bearbeiten] Aufruf
Tcl ist in den meisten Unixinstallationen bereits voreinstalliert. Mit
tclsh
wird es aufgerufen. Wenn man auch das grafische Toolkit dabeihaben will, ist
wish
aufzurufen. (Seit Tcl 8.4 reicht die tclsh in allen Fällen aus, sofern interaktiv oder im Script
package require Tk
eingegeben wird.)
expect
enthält auch Tcl und ist speziell darauf ausgerichtet bestehende Kommandozeilen-Unix-Programme, die kein GUI haben mit einer Oberfläche zu versehen.
Für andere Betriebssysteme bestehen auch verschiedene Installationspakete. Interessant ist auch das TclKit, das für Windows aus einer einzigen rund 1 MB großen Datei besteht. Durch einfaches Kopieren dieser Datei wird Tcl mit Tk und sogar einigen Zusatzpaketen verfügbar gemacht. Eine Applikation, die gerne aus vielen Dateien bestehen kann, wird in einem Starkit (eine Datei) komprimiert und zusammengepackt, und ist plattformunabhängig lauffähig, sofern ein Tclkit vorhanden ist. Die Kombination aus einem Starkit und einem Tclkit in einem einzigen File wird "Starpack" genannt – sie erlaubt, eine Applikation in einer einzigen Datei (dann allerdings plattformspezifisch) auszuliefern. Siehe http://www.equi4.com
Der Java-Wahlspruch write once – run anywhere wird hier Wahrheit; zumindest auf den Plattformen Unix (diverse), Windows (95..NT..XP..CE) und Mac.
[Bearbeiten] Incr Tcl
Incr Tcl ist ein Paket von objektorientierten Erweiterungen für Tcl und Tk. Diese ermöglichen objektorientierte Programmierung mit Tcl.
Literatur: "incr Tcl from the Ground Up" von Chad Smith Weblink: incrtcl.sourceforge.net/itcl
[Bearbeiten] Siehe auch
- Programmiersprache
- XOTcl - "Extended Object Tcl", siehe XOTcl Homepage
- STOOOP - "Simple Tcl Only Object Oriented Programming"
- Tcllib
- Jacl - "Java Command Language"
[Bearbeiten] Weblinks
Wikibooks: Tcl-Programmierung (englisch) – Lern- und Lehrmaterialien |