Tcl | |
---|---|
Skriptsprache mit Bytecode-Interpreter | |
Basisdaten | |
Paradigmen: | imperativ, funktional, objektorientiert |
Erscheinungsjahr: | 1988 |
Designer: | John Ousterhout |
Entwickler: | John Ousterhout |
Aktuelle Version | 9.0.0RC0[1] (10. September 2024) |
Typisierung: | schwach, dynamisch |
Beeinflusst von: | Lisp, Unix-Shell, C |
Betriebssystem: | Windows, Linux, macOS, Mac OS Classic, Solaris, weitere Unix-Varianten und Klone |
Lizenz: | BSD |
Tcl Developer Site |
Tcl (Aussprache englisch tickle oder auch als Abkürzung für Tool command language) ist eine Open-Source-Skriptsprache.
Tcl wurde ursprünglich ab 1988 von John Ousterhout an der University of California, Berkeley als Makrosprache für ein experimentelles CAD-System entwickelt. Aus dieser Zeit stammt das Konzept, den Tcl-Interpreter als Bibliothek in z. B. ein C-Programm einzubinden, was auch heute noch möglich ist.
Die Wahlsprüche von Tcl lauten: „radically simple“, also „radikal einfach“, was sich insbesondere auf die Syntax der Sprache bezieht, und „everything is a string“, „Alles ist Text“, was sich auf den Umgang mit Befehlen und Daten in Tcl bezieht.
Die verbreitete Kombination aus Tcl und dem GUI-Toolkit Tk wird als Tcl/Tk bezeichnet.
Die Tcl-Syntax folgt der polnischen Notation. Sie verzichtet auf reservierte Wörter, ordnet jedoch einigen Zeichen eine feste Bedeutung zu:
Alle anderen Bestandteile der Sprache können umdefiniert werden. Zwischen eingebauten und von Programmen oder Tcl-Bibliotheken hinzugefügten Funktionen besteht kein Unterschied.
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, Gleitkommazahl, Liste (Datenstruktur) oder Dict treten. Die Verwendung einer nicht definierten Variablen führt zu einem Fehler – im Gegensatz zur Programmierung mit dem Unix-Kommandozeileninterpreter (Shell) oder awk. Konstrukte wie assoziative Arrays (Hashtabelle), Listen und Dicts werden in Tcl oft angewendet. Dicts sind vergleichbar mit JSON, jedoch außer den geschweiften Klammern ohne zusätzliche Sonderzeichen wie Anführungsstriche und Doppelpunkte. Darüber hinaus gibt es Objekte mit Klassen, Mehrfachvererbung und Mixins. Letztere sind genauso wie die Steuerelemente der grafischen Oberfläche Tk Kommandos innerhalb von Tcl.
Tcl kennt sehr leistungsfähige Kommandos zur Bearbeitung von (auch langen) Zeichenketten, 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 zu arbeiten, wobei auch komplexere Ausdrücke als die von grep unterstützt werden, vergleichbar mit denen von Perl.
Zur Einbindung externer Bibliotheken besitzt Tcl ein eigenes Paketsystem, das diese auch bei Bedarf automatisch nachladen kann. Weiterhin ist es möglich, Tcl-Programme um Bibliotheken zu erweitern, die in C oder einer anderen kompilierten Sprache geschrieben sind; hierfür existiert in Form der TclStubs eine standardisierte Schnittstelle. Außerdem können mithilfe der CriTcl-Erweiterung zeitkritische Programmteile in C-Quellcode innerhalb des Tcl-Quellcodes notiert werden. Diese werden automatisch kompiliert und eingebunden.
Tcl-Programme können sich sehr einfach zur Laufzeit selbst modifizieren. Da es ohne weiteres möglich ist, eigene Kontrollstrukturen in reinem Tcl zu implementieren, ist es möglich, verschiedene Programmierparadigmen direkt in Tcl umzusetzen, zum Beispiel funktionale oder objektorientierte Programmierung.
Außerdem kann durch die Selbstmodifizierbarkeit Code aus Konfigurationsdateien oder über das Netzwerk gelesen und ausgeführt werden. Um dies in einer sicheren Form zu ermöglichen, stellt Tcl eine beliebige Zahl von Sandboxen in Form eigens gestarteter Interpreter mit beschränkter Funktionalität zur Verfügung. Diese Kind-Interpreter können jeweils mit eigenen Funktionen erweitert werden, die über definierte Schnittstellen mit ihrem Mutter-Interpreter kommunizieren.
Tcl enthält im Kern (ab Version 8.6) die bisherige Erweiterung TclOO mit Einfach- und Mehrfachvererbung sowie Mixins, sodass vollständig objektorientierte Anwendungen geschrieben werden können – aber nicht müssen. Klassen enthalten Konstruktoren und Destruktoren sowie Methoden. Im Gegensatz zu anderen Programmiersprachen sind Klassen und Objekte als Kommandos implementiert und müssen explizit mittels „destroy“ zerstört werden, was durch Überwachung von Variablen mittels „trace“ automatisiert werden kann, wenn die Variable ihren Gültigkeitsbereich verlässt.
Da es keine Zeiger gibt, wird stattdessen mittels des Objektnamens auf andere Objekte verwiesen.
Tcl implementiert nach Wunsch auch Nebenläufigkeit. Jeder Thread besitzt einen eigenen Interpreter und damit auch eigene Variablen. Ein Thread kann einen anderen Thread beauftragen, Kommandos auszuführen. Threads stehen zueinander in Eltern-Kind-Beziehung. Die Synchronisation erfolgt über Mutexes oder über „join“. Eine alternative Implementierung von Nebenläufigkeit über Coroutinen steht ab Version 8.6 ebenfalls zur Verfügung.
Tcl-Routinen werden vom Interpreter jeweils beim ersten Ausführen in Bytecode übersetzt. Beim zweiten Ausführen einer Routine steht dann bereits der Bytecode zur Verfügung, und der Programmteil läuft schneller. Es gibt auch Erweiterungen, die den gesamten Quelltext zur Ladezeit des Programms in Bytecode übersetzen.
Bekannt ist Tcl auch durch das Toolkit Tk, mit dem sich plattformunabhängige grafische Benutzeroberflächen leicht programmieren lassen. Der grafische Werkzeugkasten „Tk“ steht für eine Vielzahl von Betriebssystemen mit dem für das jeweilige System üblichen Aussehen („native look and feel“) zur Verfügung. Diese Programmierschnittstelle wird auch für viele weitere Programmiersprachen angeboten, wie z. B. Common Lisp, Perl, PHP, Ruby, Python oder R. Neben der Standard-Schnittstelle zum Tk Toolkit existieren unter anderem auch Schnittstellen zu den Toolkits FLTK und GTK+.
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.
Kommandowort param1 param2 … paramN
Anders als bei einfachen Kommandozeileninterpretern kann man in Tcl Kommandos ineinander verschachteln. Statt eines Arguments 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 entspricht dem der Backquotes bei der Unix-Shell.
Kommandowort [Unterkommando param …] …
Auch Konstrukte wie if und while oder Zuweisungen sind Kommandos. Die Kommandos folgen der Polnischen Notation, wie bei Lisp, und werden ebenfalls als Liste verarbeitet.
Tcl ist in den meisten Unix-Installationen bereits vorinstalliert oder lässt sich über die Paketverwaltung nachinstallieren, auch bei Apple macOS; nicht jedoch bei Microsoft Windows. Für andere Betriebssysteme einschließlich Windows bestehen auch verschiedene Installationspakete. Tcl ist plattformunabhängig und verhält sich auf allen Systemen, für welche es vorhanden ist, gleich. Üblicherweise wird ein Tcl-Programm (Skript) über die Tcl-Shell tclsh für Programme mit nicht-grafischer Ein-/Ausgabe oder die Tcl-Windowing-Shell wish für Programme mit grafischer Benutzeroberfläche gestartet.
Tcl wird auf der Kommandozeile, als eingebettete Sprache, als CGI-Sprache (wie sonst oft Perl), 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.
puts "Hello World!"
Hello World!
Der Befehl puts erwartet eine Zeichenkette als Eingabe und gibt diese direkt aus, gefolgt von einem Zeilenumbruch. Hier die gleiche Ausgabe unter Verwendung des Befehls zum Setzen eines Variablenwertes:
set hw "Hello World!"
puts $hw
Hello World!
proc mean data {
expr ([join $data +]) / double([llength $data])
}
Dies definiert einen neuen Befehl mean, der wie folgt aufgerufen werden kann
mean {5 4.2 1.2 6.7 9 1 0}
data ist also eine Liste von Zahlen. Der Befehl join formt aus seinem ersten Parameter $data (Inhalt von data) mithilfe des zweiten Parameters + eine Zeichenkette der Form 5+4.2+1.2+6.7+9+1+0. Diese wird nun in die Stelle eingesetzt, an der zuvor der von eckigen Klammern umschlossene join-Befehl stand. Der Befehl llength gibt die Länge einer Liste zurück. Die eckigen Klammern funktionieren hier genauso. Die Funktion double() bewirkt, dass die Zahlen nicht als Ganzzahl („integer“) mit Rest, sondern als Gleitkommazahlen mit Dezimalstellen dividiert werden (das ist bei Mittelwerten meist beabsichtigt).
Es ergibt sich für das Beispiel:
expr (5+4.2+1.2+6.7+9+1+0)/double(7)
Der Befehl expr berechnet nun den mathematischen Ausdruck.
Das Beispiel zeigt, wie einfach in Tcl Zeichenkettenverarbeitung und Berechnungen gemischt werden können, um Algorithmen einfach zu formulieren.
Tcl macht die Entwicklung grafischer Benutzerschnittstellen sehr einfach: Das folgende Mini-Programm erstellt eine Schaltfläche („button“) im Fenster, die beim Anklicken die Anwendung beendet.
package require Tk
pack [button .b -text "Goodbye World" -command exit]
Zusätzlich zum klassischen „Tk-Widget-Set“ (das sind die Bedienelemente der grafischen Benutzeroberfläche), das je nach Plattform das Aussehen von Motif, Microsoft Windows, oder Mac OS Classic simuliert, gehört ab Version 8.5 auch das Widget-Set Ttk (themeable Tk) fest zu Tk. Dabei kann ein Thema („theme“) aus einer Theme-Bibliothek ausgewählt oder selbst erstellt werden.
package require Tk
ttk::setTheme clam
pack [ttk::button .b -text "Goodbye World" -command exit]
Datenbankoperationen sind mit Tcl ebenfalls sehr einfach, wie das folgende Beispiel zeigt:
# SQLite3 einbinden
package require sqlite3
# Datenbank eröffnen
sqlite3 meinedatenbank ./meinedatenbank.sqlite
# Variable zum Referenzieren
set var 3
# Tabelle erzeugen, Fehlermeldung ignorieren
meinedatenbank eval {CREATE TABLE tabelle1 (id int, spalteA char(20))}
# Daten in Tabelle schreiben
meinedatenbank eval {INSERT INTO tabelle1 (id, spalteA) VALUES (1, 'foo'), (2, 'bar'), (3, 'ßülz')}
# Daten abfragen
meinedatenbank eval {SELECT * FROM tabelle1 WHERE id = :var} ergebnis {
puts "id = $ergebnis(id), spalteA = $ergebnis(spalteA)"
}
# Alle Daten löschen
meinedatenbank eval {DELETE FROM tabelle1}
# Tabelle löschen
meinedatenbank eval {DROP TABLE tabelle1}
# Datenbank schließen
meinedatenbank close
Dabei werden Variablenreferenzen nicht expandiert, sondern der Datenbank-„Engine“ übergeben, so dass keine Sicherheitslücke durch SQL-Injection entstehen kann.
Diese direkte Anwendung der SQLite3-Schnittstelle gilt mittlerweile als veraltet, weil es die datenbankunabhängige Schnittstelle TDBC[2] gibt, deren Name sich an ODBC und JDBC anlehnt. Im Lieferumfang von TDBC sind die Treiber für SQLite3, MySQL, ODBC (ähnlich der JDBC-ODBC-Bridge) und PostgreSQL.
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, Snit, Incr Tcl und Incr Tk sowie XOTcl ist Tcl auch objektorientiert – bis hin zur Mehrfachvererbung. Ab Version 8.6 ist TclOO im Kern enthalten, Incr Tcl basiert nun auf TclOO.