Emacs Lisp ist ein Lisp- Dialekt, der für GNU Emacs entwickelt wurde . Er wird zur Implementierung des größten Teils der in Emacs integrierten Bearbeitungsfunktionen verwendet; der Rest ist , wie auch der Lisp- Interpreter , in C geschrieben .
Emacs-Lisp-Code dient dazu, Emacs zu modifizieren, zu erweitern und anzupassen. Wer den Code nicht selbst schreiben möchte, kann stattdessen die Funktion „Anpassen“ verwenden . Diese bietet verschiedene Einstellungsseiten , auf denen der Benutzer Optionen festlegen und deren Auswirkungen in der laufenden Emacs-Sitzung in einer Vorschau anzeigen kann. Beim Speichern der Änderungen schreibt „Anpassen“ den benötigten Emacs-Lisp-Code in die Konfigurationsdatei des Benutzers . Diese kann auf eine spezielle Datei verweisen, die ausschließlich von „Anpassen“ verwendet wird, um zu verhindern, dass die Benutzerdatei versehentlich verändert wird.
Emacs Lisp ist nicht nur eine Programmiersprache , die in Bytecode [ 1 ] und nativen Code [ 2 ] kompiliert werden kann , sondern lässt sich auch als interpretierte Skriptsprache nutzen , ähnlich der Unix -Bourne-Shell oder Perl , indem Emacs im Batch-Modus aufgerufen wird . So kann es über die Kommandozeile oder eine ausführbare Datei gestartet werden, und seine Bearbeitungsfunktionen, wie beispielsweise Puffer und Navigationsbefehle, stehen dem Programm genauso zur Verfügung wie im normalen Modus. Beim Start im Batch-Modus wird keine Benutzeroberfläche angezeigt; Emacs führt einfach das übergebene Skript aus und beendet sich, wobei die Ausgabe des Skripts angezeigt wird.
Emacs Lisp wird auch als Elisp bezeichnet , obwohl es auch ältere, unabhängige Lisp-Dialekte mit diesem Namen gibt. [ 3 ] [ 4 ]
Im Vergleich zu anderen Lisp-Dialekten
Emacs Lisp ist am engsten mit Maclisp verwandt , mit späteren Einflüssen von Common Lisp . [ 5 ] Es unterstützt imperative und funktionale Programmiermethoden . Lisp war die Standard-Erweiterungssprache für Emacs-Derivate wie EINE und ZWEI . Als Richard Stallman Gosling Emacs zu GNU Emacs abspaltete , wählte er Lisp ebenfalls als Erweiterungssprache, da es leistungsstarke Funktionen bot, darunter die Möglichkeit, Funktionen als Daten zu behandeln. Obwohl der Common-Lisp-Standard noch nicht formuliert war, existierte Scheme bereits. Stallman entschied sich jedoch dagegen, da es auf Workstations (im Vergleich zu den Minicomputern , auf denen Emacs traditionell lief) vergleichsweise schlecht lief. Er wollte einen Dialekt entwickeln, der seiner Meinung nach leichter zu optimieren war. [ 6 ]
Der in Emacs verwendete Lisp-Dialekt unterscheidet sich wesentlich von den moderneren Dialekten Common Lisp und Scheme, die in der Anwendungsprogrammierung eingesetzt werden. Ein markantes Merkmal von Emacs Lisp ist die standardmäßige Verwendung dynamischer anstelle lexikalischer Gültigkeitsbereiche . Das heißt, eine Funktion kann auf lokale Variablen im Aufrufbereich zugreifen, nicht aber im Definitionsbereich. In letzter Zeit wird kontinuierlich daran gearbeitet, den Code auf lexikalische Gültigkeitsbereiche umzustellen, aus den unten erläuterten Gründen.
| 1958 | 1960 | 1965 | 1970 | 1975 | 1980 | 1985 | 1990 | 1995 | 2000 | 2005 | 2010 | 2015 | 2020 | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| LISP 1, 1.5, LISP 2 (aufgegeben) | |||||||||||||||
| Maclisp | |||||||||||||||
| Interlisp | |||||||||||||||
| MDL | |||||||||||||||
| Lisp-Maschine Lisp | |||||||||||||||
| Schema | R5RS | R6RS | R7RS klein | ||||||||||||
| NULL | |||||||||||||||
| ZIL (Zork Implementation Language) | |||||||||||||||
| Franz Lisp | |||||||||||||||
| muLisp | |||||||||||||||
| Common Lisp | ANSI-Standard | ||||||||||||||
| Le Lisp | |||||||||||||||
| MIT-Schema | |||||||||||||||
| XLISP | |||||||||||||||
| T | |||||||||||||||
| Chez Scheme | |||||||||||||||
| Emacs Lisp | |||||||||||||||
| AutoLISP | |||||||||||||||
| PicoLisp | |||||||||||||||
| Gambit | |||||||||||||||
| EuLisp | |||||||||||||||
| ISLISP | |||||||||||||||
| OpenLisp | |||||||||||||||
| PLT-Programm | Schläger | ||||||||||||||
| newLISP | |||||||||||||||
| GNU Guile | |||||||||||||||
| Visual LISP | |||||||||||||||
| Clojure | |||||||||||||||
| Bogen | |||||||||||||||
| LFE | |||||||||||||||
| Hy | |||||||||||||||
Beispiel
Die Entwicklung von Emacs Lisp wurde vom Ziel geleitet, Datenstrukturen und Funktionen bereitzustellen, die speziell für einen vielseitigen Texteditor entwickelt wurden, anstatt eine universelle Programmiersprache zu implementieren. Beispielsweise kann Emacs Lisp eine Datei nicht zeilenweise einlesen – die gesamte Datei muss in einen Emacs-Puffer geladen werden. Emacs Lisp bietet jedoch zahlreiche Funktionen zum Navigieren und Bearbeiten von Puffertext auf Satz-, Absatz- oder höherer syntaktischer Ebene, die durch Modi definiert werden.
Hier folgt ein einfaches Beispiel einer Emacs-Erweiterung, geschrieben in Emacs Lisp. In Emacs lässt sich der Bearbeitungsbereich in separate Bereiche, sogenannte Fenster , unterteilen, von denen jedes einen anderen Puffer anzeigt . Ein Puffer ist ein Textabschnitt, der in den Speicher von Emacs geladen wird (möglicherweise aus einer Datei) und in einem Textdokument gespeichert werden kann.
C-x 2Benutzer können die Standard -Tastenkombination drücken , um ein neues Fenster zu öffnen. Dadurch wird die Emacs-Lisp-Funktion ausgeführt split-window-below. Normalerweise zeigt das neue Fenster beim Erscheinen denselben Puffer wie das vorherige an. Angenommen, wir möchten, dass es den nächsten verfügbaren Puffer anzeigt. Dazu schreibt der Benutzer den folgenden Emacs-Lisp-Code entweder in eine bestehende Emacs-Lisp-Quelldatei oder in einen leeren Emacs-Puffer:
( defun my-split-window-func () ( interactive ) ( split-window-below ) ( set-window-buffer ( next-window ) ( other-buffer )))( global-set-key ( kbd "Cx 2" ) #' my-split-window-func )Die erste Anweisung (defun ...)definiert eine neue Funktion, my-split-window-funcdie split-window-belowdie alte Fensterteilungsfunktion aufruft und dem neuen Fenster anschließend mitteilt, einen weiteren (neuen) Puffer anzuzeigen. Die zweite Anweisung (global-set-key ...)bindet die Tastenkombination „Cx 2“ an die neue Funktion.
Dies lässt sich auch mithilfe der Funktion „ advice“ realisieren , die es Benutzern ermöglicht, Wrapper um bestehende Funktionen zu erstellen, anstatt eigene zu definieren. Dies hat den Vorteil, dass keine Tastenkombinationen geändert werden müssen, die Funktion überall dort funktioniert, wo die Originalfunktion aufgerufen wird, und der Code einfacher zu schreiben ist. Der Nachteil besteht jedoch darin, dass das Debuggen komplexer wird. Aus diesem Grund ist die Verwendung von advice im Quellcode von GNU Emacs nicht zulässig [ 7 ]. Benutzer können die advice-Funktion jedoch bei Bedarf in ihrem Code verwenden, um den obigen Code wie folgt zu implementieren:
( defadvice split-window-below ( after my-window-splitting-advice first () activate ) ( set-window-buffer ( next-window ) ( other-buffer )))Dies weist an, split-window-belowden vom Benutzer bereitgestellten Code bei jedem Aufruf nach der Ausführung des restlichen Funktionscodes auszuführen. Zusätzlich kann ein Advice angegeben werden, der vor der ursprünglichen Funktion, um sie herum (also die ursprüngliche Funktion buchstäblich umschließt) oder abhängig von den Ergebnissen des Advice ausgeführt wird.
Emacs 24.4 ersetzt diesen Mechanismus [ 8 ] durch , der flexibler und einfacher sein soll. [ 9 ] Der obige Rat könnte mit dem neuen System wie folgt umgesetzt werden: defadviceadvice-add
( defun switch-to-next-window-in-split () ( set-window-buffer ( next-window ) ( other-buffer )))( advice-add 'split-window-below :before #' switch-to-next-window-in-split )Diese Änderungen werden sofort nach der Codeauswertung wirksam . Es ist nicht notwendig, neu zu kompilieren, Emacs neu zu starten oder die Konfigurationsdatei neu zu aktualisieren . Wenn der Code in einer Emacs-Initialisierungsdatei gespeichert ist, lädt Emacs die Erweiterung beim nächsten Start. Andernfalls müssen die Änderungen nach einem Neustart von Emacs manuell neu ausgewertet werden.
Quellcode
Der Emacs-Lisp- Quellcode wird üblicherweise als einfache Textdatei mit der Dateinamenserweiterung „.bashrc“ im Dateisystem gespeichert . Die Benutzerinitialisierungsdatei bildet eine Ausnahme und erscheint oft als „.bashrc “, obwohl sie als beliebiger Emacs-Lisp-Code interpretiert wird. Seit Mitte der 1990er-Jahre lädt Emacs auch die Konfigurationsdateien `.bashrc` und `.bashrc`. Darüber hinaus können Benutzer über die Befehlszeile beliebige Konfigurationsdateien angeben oder explizit festlegen, dass keine Konfigurationsdatei geladen werden soll. Beim Laden der Dateien liest und analysiert eine Komponente des Emacs-Programms die Funktionen und Variablen und speichert sie im Speicher. Anschließend stehen sie anderen Bearbeitungsfunktionen und Benutzerbefehlen zur Verfügung. Funktionen und Variablen können beliebig geändert und neu definiert werden, ohne dass der Editor neu gestartet oder die Konfigurationsdatei neu geladen werden muss. .el.emacs~/.emacs.el~/.emacs.d/init.el
Um Zeit und Speicherplatz zu sparen, werden viele Funktionen von Emacs nur bei Bedarf geladen. Jede optionale Funktionsgruppe, die mit Emacs ausgeliefert wird, ist in einer Sammlung von Emacs-Code implementiert, die als Paket oder Bibliothek bezeichnet wird . Beispielsweise gibt es eine Bibliothek zum Hervorheben von Schlüsselwörtern im Quellcode und eine Bibliothek zum Spielen von Tetris . Jede Bibliothek wird mithilfe einer oder mehrerer Emacs-Lisp-Quelldateien implementiert. Bibliotheken können einen oder mehrere Hauptmodi definieren , um ihre Funktion zu aktivieren und zu steuern.
Emacs-Entwickler schreiben bestimmte Funktionen in C. Diese sogenannten Primitiven werden auch als integrierte Funktionen oder Unterfunktionen bezeichnet . Obwohl Primitive aus Lisp-Code aufgerufen werden können, lassen sie sich nur durch Bearbeiten der C-Quelldateien und anschließendes Neukompilieren modifizieren. In GNU Emacs sind Primitive nicht als externe Bibliotheken verfügbar; sie sind Bestandteil der Emacs-Programmdatei. In XEmacs ist das Laden solcher Primitiven zur Laufzeit möglich, da das Betriebssystem dynamische Verknüpfung unterstützt . Funktionen werden mitunter als Primitive geschrieben, weil sie Zugriff auf externe Daten und Bibliotheken benötigen, die in Emacs Lisp nicht verfügbar sind, oder weil sie so häufig aufgerufen werden, dass der Geschwindigkeitsunterschied zwischen C und Emacs Lisp relevant ist.
Da Fehler im C-Code jedoch leicht zu Segmentierungsverletzungen oder zu subtileren Fehlern führen können, die den Editor zum Absturz bringen, und da das Schreiben von C-Code, der korrekt mit dem Emacs Lisp Garbage Collector interagiert , fehleranfällig ist, wird die Anzahl der als Primitive implementierten Funktionen auf ein notwendiges Minimum beschränkt.
Bytecode
Die Byte-Kompilierung kann die Ausführung von Emacs-Lisp-Code beschleunigen. Emacs enthält einen Compiler , der Emacs-Lisp-Quelldateien in eine spezielle Darstellung, den sogenannten Bytecode, übersetzt . Emacs-Lisp-Bytecode-Dateien haben die Dateinamenserweiterung „ .bytecode .elc“. Im Vergleich zu Quelldateien werden Bytecode-Dateien schneller geladen und ausgeführt, benötigen weniger Speicherplatz und weniger Arbeitsspeicher.
Bytecode ist zwar immer noch langsamer als primitive Datentypen, aber als Bytecode geladene Funktionen lassen sich leicht modifizieren und neu laden, und Bytecode-Dateien sind plattformübergreifend . Der standardmäßige Emacs-Lisp-Code, der mit Emacs ausgeliefert wird, wird als Bytecode geladen, obwohl die zugehörigen Quelldateien üblicherweise ebenfalls zur Verfügung gestellt werden. Benutzerdefinierte Erweiterungen werden typischerweise nicht in Bytecode kompiliert, da sie weder so umfangreich noch so rechenintensiv sind.
Sprachliche Merkmale
Das Paket „cl-lib“ implementiert eine umfangreiche Teilmenge von Common Lisp . Es ersetzt das ältere Paket „cl“, welches bestehende Emacs-Lisp-Funktionsdefinitionen durch solche ersetzte, die eher Common Lisp ähnelten. Das Paket „cl-lib“ hingegen orientiert sich stärker an den Emacs-Lisp-Stilrichtlinien und versieht jede Funktion und jedes Makro, das es definiert, mit dem Präfix „cl-“ (z. B. `cl-` cl-defun, was nicht mit dem Namen der integrierten Funktion `cl` kollidiert defun). Dadurch werden unerwartete Verhaltensänderungen vermieden, die beim Laden des Pakets „cl“ auftreten konnten.
Emacs Lisp (im Gegensatz zu einigen anderen Lisp-Implementierungen) führt keine Endrekursionsoptimierung durch . [ 10 ] Ohne diese Optimierung können Endrekursionen schließlich zu einem Stack-Overflow führen .
Die apel- Bibliothek unterstützt das Schreiben von portablem Emacs-Lisp-Code mithilfe der Polysylabi-Plattformbrücke.
Emacs Lisp ist ein Lisp-2- ähnliches Common Lisp, was bedeutet, dass es einen Funktions-Namensraum besitzt, der von dem Namensraum für andere Variablen getrennt ist. [ 11 ]
Von dynamischer zu lexikalischer Bereichsbestimmung
Wie MacLisp verwendet auch Emacs Lisp dynamischen Gültigkeitsbereich und bietet ab Version 24 optional einen statischen (oder lexikalischen) Gültigkeitsbereich an. [ 12 ] Dieser kann durch Setzen der lokalen Dateivariable aktiviert werden lexical-binding. [ 13 ] [ 14 ] Bevor diese Option hinzugefügt wurde, konnte man das Makro aus dem (mittlerweile veralteten) Paket „cl“ verwenden, lexical-letum einen effektiven lexikalischen Gültigkeitsbereich zu gewährleisten. [ 15 ]
Bei dynamischem Scoping steht eine Variable, die innerhalb des Gültigkeitsbereichs einer Funktion deklariert wird, auch Unterprogrammen zur Verfügung, die von dieser Funktion aufgerufen werden. Ursprünglich war dies als Optimierung gedacht ; lexikalisches Scoping war noch unüblich und seine Leistung war unsicher. Der Informatiker Olin Shivers erinnert sich: „Ich fragte RMS, als er Emacs Lisp implementierte, warum es dynamisches Scoping verwendet, und seine genaue Antwort war, dass lexikalisches Scoping zu ineffizient sei.“ [ 16 ] Dynamisches Scoping sollte außerdem mehr Flexibilität für Benutzeranpassungen bieten. Es hat jedoch einige Nachteile. Erstens kann es in großen Programmen leicht zu Fehlern führen, da Variablen in verschiedenen Funktionen unbeabsichtigt interagieren können. Zweitens ist der Zugriff auf Variablen im dynamischen Scoping im Allgemeinen langsamer als im lexikalischen.
Referenzen
- ^ „Byte-Kompilierung von Emacs Lisp“ . GNU Emacs-Handbuch . Abgerufen am 14.06.2024 .
- ^ „Kompilierung von Emacs Lisp in nativen Code“ . GNU Emacs-Handbuch . Abgerufen am 14.06.2024 .
- ^ HEDRICK bei RUTGERS (Manager DEC-20's/Direktor LCSR Comp Facility (18.12.1981). ""Informationen zur Common Lisp-Implementierung"„ . Brief an rpg bei SU-AI, jonl bei MIT-AI. Archiviert vom Original am 20.09.2016 . Abgerufen am 28.07.2019 .
Wir haben inzwischen einige Erfahrung mit der Lisp-Implementierung, da Elisp (die erweiterte Implementierung von Rutgers/UCI Lisp) im Wesentlichen fertiggestellt ist.“
{{cite press release}}: CS1 Wartung: numerische Namen: Autorenliste ( Link ) - ^ „Anzeige für CCA EMACS“. Unix Review . Dezember 1984. S. 16.
CCA EMACS und Elisp sind Marken von CCA Uniworks, Inc.
- „ GNU Emacs Lisp ist stark von Maclisp und etwas von Common Lisp inspiriert. Wer Common Lisp kennt, wird viele Ähnlichkeiten feststellen. Allerdings wurden viele Funktionen von Common Lisp weggelassen oder vereinfacht, um den Speicherbedarf von GNU Emacs zu reduzieren. Manchmal sind die Vereinfachungen so drastisch, dass Common-Lisp-Nutzer verwirrt sein könnten. Wir werden gelegentlich auf die Unterschiede zwischen GNU Emacs Lisp und Common Lisp hinweisen.“ – aus dem Abschnitt „Geschichte“ der „Einführung“ im Emacs Lisp-Handbuch, Stand: Emacs 21
- „ Die Entwicklung des GNU-Betriebssystems hat mich dazu gebracht, GNU Emacs zu schreiben. Dabei war es mein Ziel, eine möglichst minimalistische Lisp-Implementierung zu erstellen. Die Größe der Programme war mir extrem wichtig. Damals, 1985, gab es Leute mit Ein-Megabyte-Rechnern ohne virtuellen Speicher. Sie wollten GNU Emacs nutzen können. Deshalb musste ich das Programm so klein wie möglich halten.“ – aus „Meine Lisp-Erfahrungen und die Entwicklung von GNU Emacs“
- ^ "Re: [Emacs-diffs] /srv/bzr/emacs/trunk r111086: gmm-utils.el (gmm-flet)" . Lists.gnu.org. 05.12.2012 . Abgerufen am 18.08.2013 .
- ^ "NEWS.24.4" .
- ^ "Alte Ratschläge weitergeben" .
- ^ „Anhang C: Portierung von Common Lisp“ . Gnu.org . Abgerufen am 28.10.2019 .
Lisp-Programmierer sollten beachten, dass der aktuelle Emacs-Lisp-Compiler die Endrekursion nicht optimiert.
- ^ "Google Groups" . groups.google.com .
- ^ „Emacs 24.1 veröffentlicht“ . Lists.gnu.org . Abgerufen am 18.08.2013 .
- ^ „Lexikalische Bindung“ . Lists.gnu.org. 1. April 2011. Abgerufen am 18. August 2013 .
- ^ „Dynamische Bindung vs. lexikalische Bindung“ . EmacsWiki. 17.05.2013 . Abgerufen am 18.08.2013 .
- ^ „Veraltete lexikalische Bindung“ . GNU Emacs Common Lisp Emulation . GNU Press . Abgerufen am 27. Mai 2021 .
- ^ "T" . People.csail.mit.edu . Abgerufen am 18.08.2013 .
Externe Links
- Offizielle Website des GNU-Projekts
- Emacs Lisp Referenzhandbuch , GNU-Projekt
- An Introduction to Programming in Emacs Lisp, GNU Project
- Emacs Lisp Elements, from Protesilaos Stavrou's website