[Richard Suchenwirth] - ''This page ("simply Tcl") is in German for even more i18n;-) It is the draft of a planned presentation. First thought of ppt or Word, but somehow I preferred the Wiki - plus allowing at least German speakers from Tclworld to discuss this while I'm writing it - best place your comments etc. at bottom of page!'' ---- '''Tcl''' (Tool command Language, ausgesprochen "tickel") ist eine einfache, aber m�chtige '''Programmiersprache'''. Da Turing-vollst�ndig, kann im Prinzip jede Aufgabe in Tcl gel�st werden, jedoch nicht immer optimal. Tcl wird (zusammen mit Perl, Python, VB) auch als '''Scriptingsprache''' bezeichnet. Zu "System-Programmiersprachen" wie C, Java, Assembler bestehen folgende Unterschiede: * nahezu typfrei ("Everything is a string") * Variablen m�ssen nicht deklariert werden - automatische Speicherverwaltung * Ausf�hrung durch Interpreter (byte-kompilierte Prozeduren) * Interaktive Nutzung m�glich, reichhaltige Introspektionsm�glichkeiten * Aussagekr�ftige Fehlermeldungen (fast "Online-Hilfe"); Weiterarbeit m�glich * Compile-Link-Zyklus entf�llt, daher schnelle Entwicklung * Wartbarkeit durch Script-Editieren bis zur Zielmaschine * Laufzeitverhalten teilweise schlechter als vollkompilierter Code Tcl kann mit '''C/C++/Java-Code f�r laufzeitkritische Teile''' auf verschiedene Weisen verbunden werden: * Einbettung (Applikation enth�lt Tcl-Interpreter) * Erweiterung (statischer oder dynamisch gelinkter Code wird f�r Tcl zug�nglich gemacht) * ''Tcl_LinkVar'': Bindung von Tcl-Variablen an C-Variablen (int, double, boolean, string) * ''Tcl_CreateObjCommand'': Bindung eines Tcl-Kommandos an eine C-Implementation * externe Server (namenlose bidirektionale Pipes) '''Tk''' (ToolKit) ist die wichtigste Tcl-Erweiterung, ein plattformunabh�ngiger GUI-Toolkit (X11, Windows, Macintosh): * extrem einfache GUI-Spezifikation * gleiche Quelldatei l�uft auf mehreren Plattformen mit "native look & feel" * Leistungsf�hige "Widgets": canvas, text, menu, scrollbar, Buttons... * Einfache aber m�chtige Geometrie-Manager: pack, place, grid * Tk wird sogar von Perl und Python als GUI-Toolkit verwendet Weitere bekannte '''Erweiterungen''': * [[incr Tcl]] - OO-Unterst�tzung �hnlich C++ * Expect - Unterst�tzung von Kommunikation zwischen verschiedenen Rechnern, "Fernsteuerung" von Applikationen * BWidget - Erweiterung von Tk um komplexere "Megawidgets" in purem Tcl * TclX - Erweiterung um Posix-Systemfunktionalit�ten Tcl bietet starke Unterst�tzung von '''Internationalisierung''' mit '''Unicode''': * alle Strings intern in Unicode/UTF-8 * Stringkonstanten mit ''\uxxxx'' k�nnen jeden Unicode darstellen * Hin- und Herkonvertierung in viele andere internationale Encodierungen * Tk: automatische Zeichensuche, falls der aktuelle Font ein gew�nschtes Zeichen nicht enth�lt * Einfache Lokalisierung mit [msgcat] Tcl vereint Konzepte aus verschiedenen Software-Welten: * LISP/Scheme: Liste als zentrale Datenstruktur, polnische Notation, Code = Daten * C: Kontrollstrukturen (for, while, if); Arithmetik * Shells: Trennung von Parsing und Ausf�hrung; cd, pwd, glob... * SNOBOL/awk: assoziative Arrays (Hashtables) * X/...: Eventmodell, ereignisgesteuerte Verarbeitung * ?: Traces - Notifikation bei Lesen/Setzen/L�schen einer Variablen Tcl hat die '''einfachste Syntax''' aller Scriptingsprachen: * keine Schl�sselw�rter, alle Kommandos werden gleich behandelt * ''Script'': Folge von Kommandos, durch \n oder ";" getrennt * ''Kommando'': Folge von W�rtern, durch Whitespace getrennt; erstes Wort ist Kommandoname * ''Wort'': whitespacelose Zeichenkette, oder gruppiert mit ".." {..} * "..": "substituiere und gruppiere mich zu einem Wort" * {..}: "gruppiere mich, aber r�hr meinen Inhalt nicht an" * Rekursiver Interpreteraufruf f�r [[..]]-eingebettete Scripts * [[..]]: "evaluiere mich zuerst zu einem String" * Variablensubstitution durch ''$name'' , Array-Elemente: ''$name($key)'' * Namensraum-Syntax: ''::foo::bar''; :: ist der globale Namensraum * Alle weitere Syntax liegt in Verantwortung der Kommandos '''Kommandos''' haben folgende Eigenschaften: * Implementation in C oder als Tcl-''proc'' * Argumente mit Defaultwert oder variabler Anzahl m�glich * jedes Kommando parst seinen Input nach eigenem Bedarf * Kommandos k�nnen umbenannt und �berladen werden * Bytecompilation beim ersten Aufruf, danach Wiederverwendung des Bytecodes * Neudefinition zur Laufzeit m�glich (''proc'' ist auch nur ein Kommando) * auch Kontrollstrukturen sind "nur" Kommandos, k�nnen �berladen oder erweitert werden * alle Variablen von Procs sind lokal, k�nnen aber mit globalen Variablen oder Variablen h�her im Callstack verbunden werden '''Strukturierung''' von Tcl-Applikationen: * Auch in Tcl kann man unwartbaren Code schreiben, mu� es aber nicht * Explizites Laden anderer Scripte mit ''source'' (''#include'' zur Laufzeit) * Automatisches Laden anderer Scripte bei Bedarf ''(auto_index)'' * Modularisierung durch ladbare ''packages'' (Script und/oder kompiliert) * Daten- und Prozedurkapselung durch Namensr�ume '''Datenhaltung in Tcl''': * Listen mit automatischer Speicherverwaltung * Assoziative Arrays (Hashtables): Schl�ssel -> Wert * �ber geeignete Schl�ssel ($i,$j) mehrdimensionale Arrays simulierbar * Formatierung von Daten aller Art (auch bin�r, mit Nullbytes) in Strings * Implizite Datenwandlung Liste <-> String <-> Zahl bei Bedarf '''Ablaufsteuerung in Tcl''': * z.B. konventionell sequentiell bzw. ''if, for, while, foreach'' * Bindung von Kommandos an GUI-Ereignisse (Maus, Tastatur) * Bindung von Kommandos an Datei-Ereignisse ''(fileevent)'' * Bindung von Kommandos an Timer-Ereignisse ''(after)'' * Bindung von Kommandos an Daten-Ereignisse (Variablen-Trace) '''Die wichtigsten Kommandos''': * [set] varname value ;# Wertzuweisung * [expr] mathexpression ;# Arithmetik und Vergleiche * [proc] name arglist {body} ;# Definition einer Prozedur * [if] {condition} {body} * [while] {condition} {body} * [foreach] iterator liste {body} ;# Iteration �ber Liste * [for] {set i 0} {$i<$max} {incr i} {...} ;# analog zu C * [return] ?value? * [break] ;# aus while/foreach/for-Schleifen * [error] "deutliche Fehlerbeschreibung" '''Die wichtigsten Listen-Kommandos:''' * [list] el... ;# Anlage einer Liste aus Einzelelementen * [lappend] listname el... ;# Anh�ngen weiterer Elemente * [lindex] list index ;# Extraktion eines Elements anhand Position * [lrange] list from to ;# Extraktion eines zusammenh�ngenden Bereichs * [lsearch] list term ;# Suche eines Elements in einer Liste * [llength] list ;# gibt die L�nge der Liste zur�ck * [split] string ?splitchars? ;# Zerlegt einen String an ''joinchars'' in Listenelemente * [join] list ?joinchars? ;# F�gt ''joinchars'' zwischen je zwei Listenelemente, erzeugt einen String '''Die wichtigsten String-Kommandos''': * [string] length/is/compare/first... * [append] varname string.. * [regexp] re string.. * [regsub] re instring replacement outvarname '''Die wichtigsten I/O-Kommandos:''' * [gets] channel ?varname? ;# bis Zeilenende (exklusiv) * [puts] channel string ;# mit Zeilenvorschub * [open] filename ?mode? ;# gibt Channel-Id zur�ck * [close] channel * [read] channel ?howmuch? ;# ohne R�cksicht auf Zeilenenden ---- Tcl hat eine kleine, aber qualifizierte weltweite '''Anwendergemeinschaft''', die vor allem auf folgenden �ffentlichen Wegen kommuniziert: * Newsgroup news:comp.lang.tcl ("die freundlichste Gruppe im Usenet") * Tcl'ers Wiki, bidirektionale Website mit reichhaltigem Inhalt * Tcl'ers Chat (manchmal weltweites Debugging in quasi-Echtzeit) ---- '''Beispiel: Berechnung des Mittelwerts einer Zahlenliste''' proc mean L {expr double([join $L +]) / [llength $L]} Die Elemente der Liste L werden mittels ''[join]'' durch "+"-Zeichen zu einem String verbunden. Dieser wird in ''[expr]'' ausgewertet, durch ''double'' in Gleitkommazahl gewandelt (um Integer-Division zu vermeiden) und durch die L�nge der Liste geteilt. Das Ergebnis von ''[expr]'' ist implizit der R�ckgabewert von ''mean''. ---- '''Beispiel: Spiegeln einer Liste''' proc lrevert L { set i [llength $L] set res {} while {[incr i -1]>=0} {lappend res [lindex $L $i]} set res } % lrevert {foo bar grill test} test grill bar foo Die Schleife �ber die Elemente der Liste beginnt mit N-1 (N als L�nge der Liste), da String- und Listenindizes ab 0 z�hlen, und endet mit 0. Die entsprechenden Listenelemente werden mit [lindex] geholt und mit [lappend] an die Ergebnisliste ''res'' geh�ngt. ''[set] res'' ist als letztes Kommando einer [proc] �quivalent zu ''[return] $res''. ---- '''Beispiel: Introspektion des eigenen Proc-Namens''' proc myProcName {} {lindex [info level -1] 0} ''[info] level'' gibt Zugriff auf den Aufrufstapel (callstack), ''info level -1'' das Kommando, mit der der Aufrufer dieser Prozedur aufgerufen wurde. Das erste Element des Kommandos ([lindex] ... 0) ist definitionsgem�� der Name. ---- '''Beispiel: Klagloser Incrementor''' Das Tcl-Kommando [incr] leistet schnelle Integer-Addition bzw. Subtraktion, vorausgesetzt die Variable existiert bereits. Damit sie im anderen Fall automatisch angelegt wird (wie bei ''awk'' �blich), faktorisieren wir die sonst erforderliche Existenzpr�fung an diese proc aus: proc inc {varname {amount 1}} { upvar 1 $varname var if {![info exist var]} {set var 0} incr var $amount } Hier wird die lokale Variable ''var'' an den in ''varname'' �bergebenen Namen einer (m�glichen) Variablen (kann auch Array-Element sein) im '''Skopus des Aufrufers''' gebunden. Damit kann ''var'' gepr�ft, intialisiert, inkrementiert werden.. und f�r den Aufrufer ist das gleiche mit ''$varname'' geschehen. ---- '''Beispiel: Zeichenh�ufigkeit''' proc charFreq string { foreach char [split $string ""] { inc t($char) } foreach {char count} [array get t] { lappend pairs [list $char $count] } lsort -integer -decreasing -index 1 $pairs } Der ''string'' wird in Einzelzeichen gesplittet, �ber die iteriert und ein Element in dem tempor�ren Array ''t'' klaglos inkrementiert wird. Der Inhalt des Arrays, eine ungeordnete flache Liste von alternierend Zeichen und Anzahl, wird in eine Liste von Paaren gewandelt, die dann bequem nach absteigender H�ufigkeit sortiert werden kann. ''String'' kann Megabytes lang und nat�rlich auch koreanisch, griechisch oder arabisch sein... % charFreq Tennessee {e 4} {n 2} {s 2} {T 1} ---- '''Beispiel: Fehlertolerantes Lesen einer Textdatei''' proc readfile {filename} { if ![catch {open $filename} fp] { set res [read $fp [file size $filename]] close $fp } else {set res {}} return $res } Wenn das �ffnen der Datei ''filename'' gelingt (der ''[catch]'' nicht anschl�gt), wird sie in ganzer L�nge in die Variable ''res'' gelesen und zur�ckgegeben. Andernfalls wird ein leerer String zur�ckgegeben. M�gliche Anwendung als Zeilenz�hler: proc wc-l filename {llength [split [readfile $filename] \n] } ---- '''Beispiel: Textausgabe in Datei, mit Sicherheitskopie''' proc text2file {text filename} { if [file exists $filename] { file rename -force $filename $filename.bak } set fp [open $filename w] puts $fp $text close $fp } Existiert eine Datei namens ''filename'', so wird sie in ''(filename).bak'' umbenannt. Dann wird eine neue Datei des Namens zum Schreiben ge�ffnet, der �bergebene String (kann beliebig lang sein) mit abschlie�endem Zeilenvorschub hineingeschrieben, und die Datei geschlossen. ---- '''Beispiel: Internet-Dateiherunterlader''' package require http http::config -proxyhost proxy -proxyport 80 puts [http::data [http::geturl [lindex $argv 0]]] Verwendet wird das mit Tcl mitgelieferte package ''http''. Mit ''http::config'' wird der hier �bliche Proxy-Rechner eingestellt. Die bei Aufruf des Scripts angegebene URL wird geladen und ihr Datenanteil (der eigentliche Inhalt) auf ''stdout'' ausgegeben, kann jedoch in eine Datei umgeleitet werden: $ tclsh ~/tcl/wwwget.tcl www.bahn.de/img/agb.gif > t.gif ---- '''Beispiel: Digitaluhr in 6 Zeilen''' proc every {ms body} { eval $body after $ms [list every $ms $body] } pack [label .clock -textvar time] every 1000 {set ::time [clock format [clock sec] -format %H:%M:%S]} Zun�chst wird ein einfacher, aber wiederverwendbarer Timer, ''every'', definiert, der den �bergebenen ''body'' (Tcl-Kommandos) ausf�hrt und anschlie�end veranla�t, da� er nach ''ms'' Millisekunden erneut aufge