2 Punkte von GN⁺ 2023-07-18 | 1 Kommentare | Auf WhatsApp teilen
  • Forth entstand aus einem kleinen Interpreter, den Chuck Moore entwickelte, um lange Compile- und Lochkarten-Abläufe zu verkürzen, und wuchs zu einem System heran, das Editor, Betriebssystem und Compiler in sich aufnahm
  • Postfix-Notation (RPN), Daten-Stack und Wörter (Dictionary) waren keine fremdartige Syntax, sondern ein Design, um auf stark eingeschränkter Hardware Verschwendung und wiederkehrende Arbeit zu reduzieren
  • Der Kern von Forth liegt in einer bootstrap-fähigen Struktur, in der selbst Elemente wie :, ;, IF, Kommentare und Variablen innerhalb der Sprache definiert und neu definiert werden können
  • Implementierungen wie JonesForth, nasmjf, PlanckForth und sectorforth zeigen, dass Forth mit einigen Dutzend bis Hundert Bytes oder wenigen Primitives beginnen und sich zu Interpreter, Compiler, Assembler und DSL erweitern kann
  • Beispiele wie Raumfahrzeuge, Open Firmware, Jupiter Ace, Canon Cat, Harris RTX2010 und GreenArrays zeigen, wie eng Forth mit interaktiver Entwicklung, kleinem Code, Hardware-Nähe und Low-Power-Computing verbunden ist

Vom Usenet-Mythos zur Erkundung von Forth

  • Dave Gauer hat seine persönliche Reise dokumentiert, auf der er Forth entdeckte und in die Computergeschichte einordnete; diese Seite ist aus kurzen Präsentationsfolien adaptiert
  • In den 1990er-Jahren waren die comp.*-Gruppen im Usenet, insbesondere comp.lang.*, wichtige Orte, um Programmieren zu lernen und darüber zu diskutieren
    • Als Beispiel wird erwähnt, dass auch Linus Torvalds’ erste Ankündigung von Linux 1991 in comp.os.minix erschien
    • Ende der 1990er-Jahre spielte Perl im frühen Web als Sprache für dynamische Seiten und Formularverarbeitung über CGI eine große Rolle
  • Legenden aus der Usenet-Zeit wie Lisp-Sprachen, der Y-Kombinator, The Little Schemer und The Story of Mel führten zur Neugier auf Forth
  • Forth begegnete dem Autor zunächst als „eine Sprache, die so flexibel ist, dass man den Wert einer Ganzzahl ändern kann“, und Chuck Moore blieb als eine Art „mad wizard“ in Erinnerung, der jedes Programm mit wenigen Bildschirmseiten Code schreiben konnte
  • Die Blogserie programming in the twenty-first century von James Hague war der letzte Anstoß zur Beschäftigung mit Forth

RPN und Stack sind nur der Ausgangspunkt

  • Der erste Eindruck von Forth ist die Postfix-Notation beziehungsweise Reverse Polish Notation (RPN)
    • Anders als bei der üblichen Infix-Notation 3 + 4 stellt Forth den Operator wie in 3 4 + hinter die Operanden
    • Das Forth-Beispiel 3 4 * 5 6 * + . gibt 42 aus
    • In dc wird dieselbe Berechnung als 3 4 * 5 6 * + p ausgedrückt
  • RPN erlaubt es, verschachtelte Ausdrücke ohne Klammern in der gewünschten Reihenfolge auszuwerten
    • 3 4 * ergibt 12, 5 6 * ergibt 30, und das abschließende + ergibt 42
    • In Forth nimmt . einen Wert vom Stack und gibt ihn aus
  • Der HP-35-Rechner ist ein wichtiges historisches Beispiel dafür, wie RPN auch außerhalb der Informatik bekannt wurde
    • Anfang der 1970er-Jahre hatte HP leistungsstarke Desktop-Rechner; der HP-35 wird als Beispiel dafür vorgestellt, diese Rechenleistung in einen „shirt pocket“-Rechner zu bringen
    • HP-Rechner waren für ihre RPN-Syntax bekannt; RPN ist effizient, wirkte auf Außenstehende aber etwas schwer zugänglich
  • Das zweite Merkmal ist der Daten-Stack
    • Operationen wie PUSH, POP, SWAP und DUP sind zugleich Forth-Wörter
    • Gibt man eine Zahl ein, landet sie auf dem Stack; Operatoren nehmen Werte vom Stack, berechnen damit ein Ergebnis und legen es wieder darauf ab
  • Der Stack reduziert die Notwendigkeit, Zwischenwerten Namen zu geben
    • In vielen imperativen Sprachen braucht man temporäre Namen wie result2 oder matched_part3
    • Arbeiten ohne Namen wird auch als implizites, tacit oder point-free programming bezeichnet
    • Forth nur über RPN und Stack zu verstehen, greift zu kurz; als Ausgangspunkt zum Verständnis seiner historischen Wurzeln ist es aber sinnvoll

Concatenative Programming und Joy – und worin sich Forth unterscheidet

  • Wer Forth erkundet, stößt auf das Konzept des concatenative programming
    • Ein applicative Beispiel ist eat(bake(prove(mix(ingredients))))
    • Ein concatenative Beispiel ist ingredients mix prove bake eat
    • Funktionen werden der Reihe nach aufgelistet, und die Werte jeder Stufe werden implizit an die nächste weitergereicht
  • Joy ist ein repräsentatives Beispiel einer concatenative language
    • Manfred von Thun wurde von John Backus’ ACM-Turing-Award-Vorlesung von 1977 „Can Programming Be Liberated from the von Neumann Style?“ inspiriert
    • In Joy nimmt jede Funktion einen Stack als Eingabe und gibt einen Stack als Ausgabe zurück
    • Ein Programm ist eine von links nach rechts gelesene Liste von Funktionen
  • Joys Quotations und Kombinatoren zeigen eine Rechenweise ohne Variablen
    • JavaScripts [1, 2, 3, 4].map(n => n + 1) erzeugt [2,3,4,5]
    • In Joy erzielt man dasselbe Ergebnis mit [1 2 3 4] [1 +] map
    • [] ist in Joy ein Quotation-Mechanismus, der nicht nur Daten, sondern auch Programme enthalten kann
  • Kombinatoren werden als Higher-Order Functions behandelt, die Funktionen als Eingabe erhalten
    • map() ist ein Beispiel dafür, Boilerplate für die Iteration über Listen zu abstrahieren
    • Die Kombinatoren I, K und S sowie der SKI-Kalkül erscheinen als Bausteine zur Beschreibung universeller Berechnung
    • Schon S und K allein können ein vollständiges System für universelle Berechnung bilden
  • Auch Forth kann mit Execution Tokens und dem Wort EXECUTE Higher-Order Functions bauen
    • FOO EXECUTE führt das Wort aus, das das Wort FOO zurückgegeben hat
    • Combinatorial Words wie MAP, FOLD und REDUCE lassen sich definieren
  • Forth und Joy ähneln sich äußerlich in der Syntax, interpretieren Ausdrücke aber unterschiedlich
    • In Forth liest man 2 3 + als „2 und 3 auf den Stack pushen und addieren“
    • In Joy liest man es als „Die Komposition der Funktionen 2, 3 und + ist identisch mit der Funktion 5“
    • Forth ist weniger eine Sprache, die aus abstrakten Prinzipien des concatenative computing hervorgegangen ist, sondern eher eine Sprache, die in der Interaktion mit Hardware gewachsen ist

Chuck Moores Weg zur Entwicklung von Forth

  • 1958 nutzte Chuck Moore während seiner Zeit am Smithsonian Astrophysical Observatory und am MIT Fortran und den IBM 704
    • In Forth, the Early years sagte Moore: „Compiling took 30 minutes...you got one shot per day“
    • Der IBM 704 war ein raumfüllender Röhrencomputer; zugleich wird zitiert, dass er im Schnitt etwa alle 8 Stunden ausfiel
  • Um Neukompilierungen zu reduzieren, entwickelte Moore einen einfachen Interpreter, der Karten las, mit denen das Programm gesteuert wurde
    • Ohne recompile ließen sich unterschiedliche equations für mehrere satellites konfigurieren
    • Das free-form input format war für Menschen zuverlässiger zu schreiben als die formatted columns von Fortran
    • Dieses System wurde zum Ursprung dessen, was später Forth heißen sollte
  • 1961 schrieb Moore in Stanford auf einem Burroughs B5500 eine mathematical application namens CURVE
    • CURVE enthielt einen ausgefeilteren interpreter, einen data stack und control flow operators
    • Die Funktionen entsprachen ungefähr Forth-Wörtern wie IF ELSE DUP DROP SWAP + - *
    • Mit parameter stack und der Möglichkeit, neue procedures zu definieren, entstand eine Struktur, die Forth bereits nahekam
  • Um 1965 wurden mit Teletype, paper tape, timesharing und interactive terminals die Umgebungen interaktiver, und auch Forth wurde interaktiver
    • Wörter wie KEY, EMIT, CR, SPACE und DIGIT kamen hinzu
    • Diese Wörter verwandelten Moores System in einen program editor, sodass Nutzer ein program innerhalb des program bearbeiten konnten
  • 1968 arbeitete Moore bei Mohasco mit einem IBM 1130 und gab dem System den Namen „FORTH“
    • Der IBM 1130 war ein 16-Bit-System mit 8 KB RAM, und Dateinamen waren auf 5 Zeichen begrenzt
    • Moores „fourth generation“-System wurde wegen der 5-Zeichen-Beschränkung zu FORTH
    • In dieser Zeit kamen ein return call stack und ein word dictionary hinzu
  • Forths benanntes word dictionary dient als zentrale Abstraktion
    • : DOUBLE DUP + ;
    • : QUAD DOUBLE DOUBLE ;
    • Ohne return stack könnte die Ausführung nach DOUBLE nicht zur verbleibenden Position in QUAD zurückkehren

NRAO, Portierung und indirect threaded code

  • Anfang der 1970er schrieb Moore am National Radio Astronomy Observatory Software zur Computersteuerung für Radioteleskope
    • Das NRAO hatte eine Richtlinie, auf Minicomputern Fortran zu verwenden, doch aufgrund früherer Erfolge erhielt Moore die Erlaubnis, Forth einzusetzen
    • Beim spectral-line observing konnten während der Datenerfassung spectra angezeigt und line-shapes per least-squares angepasst werden
    • Diese Arbeit brachte den Stand der Technik bei online data reduction voran; Astronomen nutzten sie, um inter-stellar molecules zu entdecken und zu kartieren
  • Elizabeth „Bess“ Rather übernahm Forth und schrieb 1972 das erste Forth-Handbuch
    • Später gründete sie zusammen mit Chuck Moore FORTH, Inc
    • Bis zu ihrem Ruhestand 2006 blieb sie eine der wichtigsten Expertinnen und Promoterinnen der Forth language
  • Forth wurde auf mehrere Maschinen portiert, darunter IBM 360/50, Honeywell 316, Honeywell DDP-116 und DEC PDP-11
    • Die Forth-Implementierung für den H316 wurde auf dem Computer selbst programmiert und zum Erzeugen anderer Forths genutzt; sie gilt daher als erste complete, stand-alone implementation
    • Der PDP-11 ist ein wichtiger Minicomputer, der mit der Geschichte von Unix und der Programmiersprache C verbunden ist
  • Dass sich Forth auf verschiedene Maschinen portieren ließ, lag unter anderem an indirect threaded code
    • Threaded code hat hier nichts mit concurrency oder multi-threaded programming zu tun
    • Threaded code speichert statt subroutine call instructions eine Liste von subroutine addresses
    • Um die address list auszuführen, braucht es einen code interpreter
  • Indirect threaded code speichert keine Liste von Adressen, die direkt auf Code zeigen, sondern eine Liste von Adressen, die auf Adressen zeigen, die auf Code zeigen
    • Durch diese zweite Indirektion kann es für unterschiedliche Arten von subroutines jeweils einen eigenen inner interpreter geben
    • In Forth ist der outer interpreter der Teil, mit dem Nutzer am Terminal interagieren, während der inner interpreter den Rest eines word ausführt
  • Zu diesem Zeitpunkt war Forth über einen einfachen command interpreter hinausgewachsen: zu einer interactive language, einem editor, operating system sowie einer Methode zur code storage and execution
    • Merkmale wie postfix notation, stack-oriented und concatenative style, interpreted, hochgradig an machine architectures anpassbar und extremely compact lassen sich so zusammenfassen
    • Forth ist keine 1958 auf einmal entworfene Sprache, sondern das Ergebnis dessen, was Moore passend zu seinen Bedürfnissen und neuer hardware wachsen ließ

Um Forth zu verstehen, muss man Forth implementieren

  • In dem Rat „To understand Forth, you have to implement a Forth“ ist das wichtige Wort a Forth
    • Aus Chuck Moores Sicht ist ein Forth system am besten, wenn es maßgeschneidert an system und task angepasst wird
  • Bevor der Autor den JonesForth-Quellcode bearbeitete, schrieb er Assembly Nights, um Grundlagen von Assembly und der Linux ABI zu lernen
    • JonesForth verwendet i386-Assembly-Quellcode, geschrieben für den GNU GAS assembler
    • Es ist ausschließlich 32-bit und nutzt direkt die Linux system call ABI
    • Der Autor verbrachte etwa ein Jahr damit, JonesForth auf eine mit dem NASM assembler lauffähige Kopie zu portieren; dieser Port ist nasmjf
  • Beim Portieren von nasmjf lernte er, wie traditionelles indirect threaded Forth funktioniert
    • JonesForths jonesforth.S ist eine einzelne Datei mit dem Assembly-Teil; Richard W.M. Jones führt mit ASCII art und Erklärungen durch den Ablauf des interpreters
    • Um sein Verständnis zu ordnen, erstellte der Autor im nasmjf-Quellcode mehrere ASCII-art-Diagramme
  • Das Macro NEXT ist der zentrale Ablauf, der nach der Ausführung eines word zum nächsten word übergeht
%macro NEXT 0
    lodsd     ; NEXT: Load from memory into eax, inc esi to point to next word.
    jmp [eax] ; Jump to whatever code we're now pointing at.
%endmacro
  • lodsd verschiebt ein double word aus dem memory nach eax und aktualisiert den Zeiger auf die nächste Position
  • jmp [eax] überträgt die Ausführung an die aktuell referenzierte Stelle und wird zum inner interpreter der jeweiligen subroutine
  • Im traditional Forth gibt es grundsätzlich code words und colon words
    • Ein code word ist ein in machine code geschriebenes primitive
    • Ein colon word ist ein normales, in der Forth language geschriebenes word und wird mit dem : compiler zusammengesetzt
    • Ein colon word endet mit EXIT; EXIT verarbeitet den return stack und setzt den Ablauf anschließend mit NEXT fort
  • Forth ist eine Struktur, in der sehr kleine Teile zusammenarbeiten und ein running system bilden
    • Auf niedriger Ebene gewinnt man Flexibilität und Einfachheit, auf hoher Ebene kann jedoch die Verständlichkeit darunter leiden

Code-Words, Colon-Words und Compiler laufen auf demselben Interpreter

  • SWAP, DUP und DROP zeigen, wie direkt Forth-Primitives als Machine Code implementiert werden können
DEFCODE "SWAP",SWAP,0
    pop eax
    pop ebx
    push eax
    push ebx
NEXT
DEFCODE "DUP",DUP,0
    mov eax, [esp]
    push eax
NEXT
DEFCODE "DROP",DROP,0
    pop eax
NEXT
  • JonesForth verwendet den i386-Call/Return-Stack als Forth-Parameter-Stack und implementiert Stack-Operationen daher mit nativen pop- und push-Instruktionen
  • In nasmjf gibt es 130 Code-Words, die meisten davon aus Effizienzgründen
    • Für die Zahl der Machine-Code-Words, die ein bootstrappbares Forth-System benötigt, gibt es ein theoretisches Minimum
    • Reduziert man die Zahl der Primitives zu stark, kann der übrige Forth-Code ineffizient und verkrampft werden
    • Frank Sergeants A 3-INSTRUCTION FORTH FOR EMBEDDED SYSTEMS WORK behandelt ein 3-Instruction-Forth für den Motorola MC68HC11, das nur 66 Byte benötigt
    • sectorforth ist ein 16-Bit-x86-Forth, das in einen 512-Byte-Bootsektor passt
  • Ein Colon-Word ist eine Methode, aus der Komposition bestehender Words ein neues Word zu erzeugen
: SDD SWAP DROP DUP ;
  • SDD hat denselben Effekt, als würde man nacheinander SWAP DROP DUP aufrufen
  • Aus Sicht von indirect threaded code ist ein Colon-Word in die Inner-Interpreter-Adressen der drei Code-Words kompiliert
  • : und ; sehen wie Syntax aus, sind tatsächlich aber Forth-Words
    • : nimmt den Namen eines neuen Words entgegen und schaltet den Compile Mode ein
    • ; vervollständigt den neuen Dictionary-Eintrag und schaltet den Compile Mode aus
    • Nutzer können : selbst durch eine eigene Definition ersetzen und Forth damit erweitern oder verändern
    • Die einzige Syntax von Forth wird als Whitespace zwischen Input-Tokens behandelt
  • Kompilieren bedeutet in Forth, Word-Adressen oder Literale zusammen mit Push-Code in den Speicher zu schreiben
    • Im Normal Mode wird ein Word sofort ausgeführt
    • Im Compile Mode wird die Word-Adresse im Speicher abgelegt
    • Derselbe Interpreter führt sowohl Code aus als auch kompiliert Code
  • Auch Control Structures wie IF...THEN lassen sich in Forth selbst implementieren
: IF IMMEDIATE ' 0BRANCH , HERE @ 0 , ;

: THEN IMMEDIATE DUP HERE @ SWAP - SWAP ! ;
  • Dass selbst so fundamentale Elemente wie IF innerhalb der Sprache definiert werden, ist die zentrale Begründung für den Titel „The programming language that writes itself“
  • Auch der verschachtelte Kommentar ( ... ) ist in jonesforth.f in Forth implementiert
    • Sogar Kommentare werden innerhalb der Sprache implementiert, und Nutzer können sie neu definieren oder eigene Kommentarformen hinzufügen
    • Dieses Beispiel unterstreicht, dass Forth fast keine native Syntax besitzt

Dictionary und Neudefinitionen schaffen Erweiterbarkeit

  • Das Forth-Dictionary verwendet traditionell eine verkettete Liste; die Wortsuche beginnt beim neuesten Eintrag
    • Die neueste Definition eines Words mit demselben Namen verdeckt frühere Definitionen
    • Jedes Word kann neu definiert werden, auch solche, die ursprünglich in Assembly definiert wurden
    • Bereits kompilierte Words speichern keine Namen, sondern Adressen, und verweisen daher weiter auf die Adresse des Words vor der Neudefinition
  • In einer neuen Definition kann man das frühere Word gleichen Namens aufrufen und so ein Word erweitern
    • Beim Erzeugen rekursiver Words versteckt : das gerade kompilierte Word im Dictionary oder markiert es als inaktiv
    • Um innerhalb des aktuellen Words sich selbst aufzurufen, ist RECURSE nötig
  • Das aus Leo Brodies Thinking Forth übernommene und abgewandelte Beispiel mit Apfel-Variablen zeigt die Flexibilität von Forth
    • VARIABLE APPLES erzeugt ein Word APPLES, das bei Aufruf eine Speicheradresse auf den Stack legt
    • 20 APPLES ! speichert 20 an dieser Adresse
    • APPLES ? holt den Wert und gibt ihn aus
    • Thinking Forth (PDF) ist kostenlos verfügbar
  • Selbst wenn rote und grüne Äpfel getrennt verfolgt werden müssen, muss bestehender Code, der APPLES verwendet, nicht geändert werden
VARIABLE COLOR

VARIABLE REDS
: RED REDS COLOR ! ;

VARIABLE GREENS
: GREEN GREENS COLOR ! ;

: APPLES COLOR @ ;
  • Auch das neue APPLES ist ein Word, das eine Adresse auf den Stack legt, daher bleibt die Nutzung mit APPLES ! und APPLES ? erhalten
  • Die Adresse wechselt lediglich je nach aktiver Apfelfarbe zu REDS oder GREENS
  • Aus Sicht gewöhnlicher Sprachen wirkt es, als wäre eine Variable zu einer Funktion geworden; in Forth jedoch ist auch eine Variable ein Word, das eine Adresse auf den Stack legt, und eine Funktion ist ebenfalls ein Word, sodass sich auf Sprachebene kein Konzept ändert
  • Auch Tokens, die wie Zahlen aussehen, können als Dictionary-Words neu definiert werden
: 4 12 ;
  • Führt man ." The value of 4 is " 4 . CR aus, wird The value of 4 is 12 ausgegeben

Meow5 und Forth als „Weg des geringsten Widerstands“

  • nasmjf, die Portierung von JonesForth nach NASM, war keine Rekonstruktion von Moores Prozess, sondern eher eine Übung, bei der das Endprodukt als „master copy“ genau untersucht wurde
  • Danach führte der Autor ein extremes Experiment mit concatenative programming namens Meow5 durch
    • Meow5 ist ein Experiment, bei dem sämtlicher Code immer aneinandergehängt und inline gesetzt wird
    • Es ist concatenative, weil es wie Forth das Konzept eines Parameter-Stacks verwendet
    • Es war ein Gedankenexperiment, das die Frage vorantrieb, was passiert, wenn man statt Funktionsaufrufadressen vollständige Funktionskopien speichert
  • Der Kern von Meow5 besteht darin, jedes Word zu 100 % inline zu setzen
    • Ausgangspunkt war inline expansion, eine übliche Optimierung zur Vermeidung kleiner Funktionsaufruf-Overheads
    • Ein Primitive wie DROP, das aus einer einzigen Instruktion besteht, über mehrere Sprünge aufzurufen, wirkte verschwenderisch
  • Meow5 endete als „vergnüglicher kleiner Fehlschlag“
    • Das Inlining von Machine Code selbst funktionierte gut, und die erzeugten ELF-Executables verhielten sich wie beabsichtigt
    • Das Problem waren String-Daten: Man musste Strings jedes Mal kopieren oder kompliziert nachverfolgen, welches Word welchen String verwendet
    • Das Forth-Word INLINE, das selektives Inlining anbietet, wurde als bessere Lösung bewertet
  • Auch bei der String-Syntax bestätigte sich Moores Rat erneut
    • In Forth verwendet man das Word ", daher ist wie in " Hello World." ein Leerzeichen erforderlich
    • Meow5 übernahm einen natürlicheren Quoting-Stil der Form "Hello World." sowie Escape-Sequenzen wie \n und \"
    • Wegen dieser Entscheidung musste an vielen Stellen im Tokenizer und Interpreter eine Sonderbehandlung für " eingebaut werden, wodurch Reinheit und Einfachheit abnahmen
  • Wenn man beginnt, dem Forth-Pfad zu folgen, ergibt sich der Rest, als würde er sich „von selbst schreiben“
    • Forth ist Bootstrapping, Metaprogrammierung und kann zu OS und IDE/Editor werden
    • Daraus folgt die These, dass man am Ende etwas Forth-Ähnliches schreiben könnte, wenn man den einfachsten Interpreter für eine völlig neue CPU-Architektur baut

Kleine Forth-Implementierungen und praktische Einsatzgebiete

  • Forth kann innerhalb von Forth weiteres Forth definieren, und viele Forths enthalten auch einen Assembler
    • Am Ende von JonesForth gibt es einen Stub für einen Assembler, der in Forth läuft
    • ;CODE aktualisiert den Header so, dass das Codeword nicht auf DOCOL, sondern auf den assemblierten Code zeigt
  • PlanckForth ist ein handgeschriebenes Forth-Binary mit weniger als 1 KB
    • Eine vollständige ELF-Binärdatei und eine funktionierende Forth-Implementierung passen in weniger als 1 KB
    • bootstrap.fs beginnt mit anfangs schwer verständlichen Operatoren und wird nach einigen hundert Zeilen zu gut lesbarem Forth
  • Kleine Implementierungsbeispiele zeigen die extreme Komprimierbarkeit von Forth
    • SmithForth ist ein von David Smith handgeschriebenes Machine-Code-Forth und wird als Forth-System mit 1.000 Byte und 1.000 Zeilen vorgestellt
    • sectorforth ist ein Forth für einen 512-Byte-Bootsektor
  • Forth wird in Kraftwerken, Robotik, Raketenverfolgungssystemen, industrieller Automatisierung, eingebetteten Sprachen in Videospielen, Datenbanken, Buchhaltung, Textverarbeitung, Grafik, Rechensystemen, dem Open-Firmware-Bootloader sowie auf verschiedenen Prozessoren und Mikrocontrollern eingesetzt
  • Open Firmware ist ein wichtiges Beispiel aus dem Engineering von Sun Microsystems
    • Da es auf einer interaktiven Programmiersprache basiert, lassen sich neue Hardware effizient testen und in Betrieb nehmen
    • Im Fall des Space Shuttle ESN wird Open Firmware als Werkzeug behandelt, mit dem sich Hardware, Software, Plug-in-Treiber und sogar die Firmware selbst debuggen lassen
  • Jupiter Ace war ein britischer Heimcomputer von 1982, dessen Betriebssystem Forth war
    • Das OS und die Routine-Library passten in ein 8-KB-ROM
    • Es gibt ein Zitat aus dem Jahr 1982, wonach das eingebaute Forth „10-mal schneller“ als interpretiertes BASIC war und weniger als die Hälfte des Speichers benötigte
  • Beim Canon Cat von 1987 war das Betriebssystem Forth; OS, Office-Suite und Programmierumgebung steckten in einem 256-KB-ROM
    • Das Produkt setzte Jef Raskins tastaturzentrierte Oberfläche und Designphilosophie in Hardware und Software um
    • Der Einstieg in die Forth-Oberfläche wirkt nicht wie der primäre Nutzungsablauf, ist aber mit Kenntnis der Prozedur mit wenigen Tastendrücken möglich

Weltraumsoftware und Forth

  • Eines der interessanten Einsatzgebiete von Forth ist die Weltraumforschung
    • Weil Raumfahrzeuge teuer sind und Reparaturzugang schwierig oder unmöglich ist, ist Softwarezuverlässigkeit wichtig
    • Die Liste der NASA-Projekte, die Forth verwenden, ist lang; der ursprüngliche Link ist verschwunden, aber es gibt Kopien in der Wayback Machine und auf forth.com
  • Das Space Shuttle Small Payload Accommodations Interface Module (SPAIM) ist ein Beispiel für den Einsatz von Forth
    • Das Entwicklungsteam schrieb Forth-Routinen auf dem PC, lud sie herunter und testete sie interaktiv
    • Es gibt ein Zitat, wonach die SPAIM-Flugsoftware während der Shuttle-Mission STS-45 problemlos funktionierte
    • Das Forth-System von SPAIM war multitaskingfähig, jede Task hatte ihren eigenen Stack, und eine Watchdog-Task überwachte den Stack-Zustand
  • Der Space Shuttle Robot Arm Simulator ist ein Beispiel dafür, wie ein einzelner Programmierer ein komplexes Gerät in fünf Wochen entwickelte
    • Er musste Befehle eines 3-Achsen-Joysticks entgegennehmen und damit einen 50 Fuß langen Arm mit 6 Gelenken und 6 Koordinatensystemen steuern
    • Es wird zitiert, dass das System 14 separate Prozesse hatte
    • Es gibt ein Zitat, wonach die Simulationstests so gründlich waren, dass der Executive-Control-Algorithmus nach der Installation vor Ort nicht geändert wurde
  • Das Shuttle Mission Design and Operations System (SMDOS) war bodengestützte Steuerungssoftware des JPL
    • Während der SIR-B-Mission wurde auf mehrere Hardwareausfälle vor Ort mit Softwareänderungen reagiert
    • Wegen Antennenproblemen und Bahnänderungen war eine neue Strategie zur Datenerfassung nötig, und SMDOS wurde genutzt, um Pläne anzuzeigen, die zu den neuen Bedingungen passten
    • Viele Daten gingen verloren, aber mit einer Rotieren-Erfassen-Rotieren-Übertragen-Methode wurden 20 % der Daten gerettet
  • Der Harris RTX2010 war Forth-Hardware, die in vielen Weltraumanwendungen eingesetzt wurde
    • Direkte Ausführung von Forth
    • Zwei Hardware-Stacks mit 256 Word Tiefe
    • 8-MHz-Takt und niedrige Latenz
    • Strahlungsgehärtete Eigenschaften
  • Rosetta und Philae werden als erste Mission vorgestellt, bei der eine Raumsonde einen Kometen umkreiste und ein Lander auf der Kometenoberfläche abgesetzt wurde
    • Der Ion and Electron Sensor von Rosetta nutzte den Harris RTX2010
    • Der Philae-Lander nutzte zwei RTX2010 im CDMS und zwei weitere für die ADS-Steuerung
    • Rosetta war von 2004 bis 2014 unterwegs und traf dann auf 67P/Churyumov-Gerasimenko
    • 67P ist 4 km breit und umkreist die Sonne alle sechseinhalb Jahre
  • Philae erlebte wegen des Versagens von Harpunen und Landetriebwerk einen Bounce in der geringen Schwerkraft an der Oberfläche, war aber robust genug, um „80 %“ der wissenschaftlichen Mission zu erfüllen
  • Auch der Fall eines Code-Patches für das Galileo-Magnetometer von 1993 kommt vor
    • Das Magnetometer hatte einen RCA1802, 2 KB RAM und 2 KB ROM und wurde mit einem Apple-II-basierten Entwicklungssystem in Forth programmiert
    • Mitten im Gerätecode entstand ein fehlerhaftes Speicherbyte, sodass ein Patch nötig war, der die Nutzung dieses Bytes vermied
    • Der Zitierte schrieb in Lisp von Grund auf eine Forth-Entwicklungsumgebung und einen Hardware-Simulator für dieses Gerät, um den Patch zu erzeugen; in Teilzeit dauerte das weniger als drei Monate

Forth ist eher Idee und Abstammungslinie als eine einzelne Implementierung

  • Forth ist weniger eine einzelne Referenzimplementierung als vielmehr eine Idee mit gemeinsamen Konzepten und einer Abstammungslinie
  • Einer der Gründe, warum Forth schwer zu lernen ist, liegt darin, dass es keine einzelne Implementierung gibt, die den Namen „Forth“ exklusiv repräsentiert
    • Einige frühe Forths gab es schon vor dem Namen „Forth“
    • Die Forth-Standards setzen sich aus den ANS-Forth-Dokumenten fort; erwähnt werden der Forth 2012 Standard und das Forth200x Committee
  • Forths teilen Konzepte und gemeinsame Words, aber zweckspezifische Forths haben ihr eigenes Spezialvokabular
  • Chuck Moore gründete 1973 Forth, Inc, portierte Forth seitdem auf verschiedene Systeme und entwickelt weiterhin neue Systeme
  • colorForth ist eine spätere Umgebung von Chuck Moore
    • Farben im Quellcode ersetzen einen Teil der Satzzeichen des Standard-Forth und bestimmen, wie Words verarbeitet werden
    • Die Farben vereinfachen die Semantik von Forth, erhöhen die Compile-Geschwindigkeit und helfen, wie dargestellt, auch Moores schlechter Sehkraft
    • colorForth enthält ein eigenes 63-KB-Betriebssystem
  • Moore sieht Software als etwas, das durch immer neue Funktionen komplexer wird, bis niemand sie aus Angst vor unbeabsichtigten Folgen noch ändern kann
    • Daraus folgt seine These, nötig sei ein dedizierter Programmierer, der seine Karriere einer einzelnen Anwendung widmet und sie durch wiederholtes Neuschreiben perfektioniert

Maschinennähe, Forth-Chips, GreenArrays

  • Chuck Moore stellt sich seit den 1950er-Jahren gegen Software-Komplexität; es werden Zitate angeführt, in denen er Betriebssysteme wie Windows, UNIX und DOS als unverständlich oder unnötig betrachtet
  • Der Autor beschreibt Moores Philosophie als Mechanical Sympathy
    • Der Ausdruck stammt aus einem Zitat des Formel-1-Fahrers Jackie Stewart und wurde im Software-Kontext von Martin Thompson in Why Mechanical Sympathy? verwendet
    • Forth ist tendenziell bei „Hardware-Leuten“ wie Elektroingenieuren und Entwicklern eingebetteter Systeme beliebt
  • Chuck Moores eigentliche Leidenschaft scheint im Prozessordesign zu liegen
    • Harris RTX2000 und RTX2010 werden im Grunde als Moores Chips vorgestellt
    • Moore entwarf seit dem Novix N400 Gate Array von 1983 Hardware; ein verbessertes Design wurde an Harris verkauft und wurde zu den RTX-Chips
  • Moore entwirft Prozessoren mit seiner eigenen, in 500 Zeilen Forth geschriebenen VLSI-Software OKAD
    • VLSI Design Tools (OKAD) beschreibt, dass 500 Zeilen colorForth alles bereitstellen, was für das Chipdesign nötig ist
    • OKAD ist eine Werkzeugsammlung, die Logikgatter-Technik, Schaltungslayout, Simulation des elektrischen Verhaltens und GDSII-Export umfasst
  • Novix NC4000 ist eine extrem schnelle Processing Engine, die dafür entwickelt wurde, High-Level-Forth-Befehle direkt auszuführen
    • Leistung wird dadurch erzielt, dass gewöhnliche Assembly Language und internes Microcode entfallen
    • Die Dual-Stack-Architektur reduziert den Overhead bei der Implementierung von Subroutines erheblich
  • GreenArrays-Chips werden anhand von Moores Vortrag „Programming a 144-computer chip to minimize power“ aus dem Jahr 2013 vorgestellt
    • Ein einzelner Chip enthält 144 asynchrone Computer
    • Ein inaktiver Core verbraucht 100 nW, ein aktiver Core 4 mW, läuft mit 666 Mips und kehrt anschließend in den Leerlauf zurück
    • Wenn alle Computer mit maximaler Geschwindigkeit arbeiten, beträgt die Leistungsaufnahme 550 mW, also etwa 0,5 W
  • Das GreenArrays-Architecture-Dokument betont „NO CLOCKS“
    • Es wird erklärt, dass die Erzeugung und Verteilung des Takts in gewöhnlichen Computern auch im Leerlauf viel Energie verbraucht, ohne etwas zu leisten
    • GreenArrays wird nicht als Multi-Core-CPU, sondern als Multi-Computer System vorgestellt

Einfachheit, Effizienz und die Zukunft des Low-Power-Computing

  • Der Autor sieht Software und Hardware als auf einem Weg, auf dem immer weitere Schichten von Komplexität aufgebaut wurden
    • Computing in großen Rechenzentren wird als billig oder kostenlos wahrgenommen, weil es indirekt über Werbekosten bezahlt wird
    • Tatsächlich bezahlt werde mit der Aufmerksamkeit und den persönlichen Daten der Nutzer, erklärt er
  • Er argumentiert, dass es künftig keinen Grund mehr gibt, immer ineffizientere und schlechter gemachte Software sowie immer steilere Hardware-Anforderungen weiter zu verwenden
  • Forth-ähnliche Sprachen könnten in folgenden Bereichen eine starke Zukunft haben
    • kleine, allgegenwärtige Computer
    • Solarstrom
    • stark eingeschränkte VMs
  • Dennard-Scaling kam um 2006 weitgehend zum Stillstand
    • Der Zusammenhang, nach dem kleinere Transistoren höhere Geschwindigkeiten und niedrigere Spannungen ermöglichten, erreichte wegen Leckströmen und Wärme bei etwa 4 GHz eine Stagnation
    • Herb Sutters The Free Lunch Is Over behandelt, wie sich die Art der CPU-Leistungssteigerung zu Hyper-Threading und Multicore verlagert
  • Sutter meint, Anwendungen müssten für Nebenläufigkeit neu entworfen werden oder man müsse effizienteren, weniger verschwenderischen Code schreiben
    • Er sagt, Performance-Optimierung werde nicht weniger wichtig, sondern wichtiger werden
  • Heute kann man für ein paar Münzen einen Microcontroller kaufen, der deutlich leistungsfähiger ist als ein IBM 704, und darauf ein leistungsfähiges Forth-System schreiben
    • Ein Microcontroller kann mit einer Knopfzelle oder einem kleinen Solarpanel betrieben werden
    • Daran schließt die Formulierung an, dass es nie eine erstaunlichere Zeit für Computing im Kleinen gegeben habe
  • Um Forth zu verstehen, muss man den Unterschied zwischen „simple“ und „easy“ berücksichtigen
    • Rich Hickeys Simple Made Easy wird als Vortrag vorgestellt, der diese Unterscheidung überhaupt erst benennbar gemacht habe
    • Forth ist nicht einfach zu lernen und vielleicht nicht immer angenehm, aber es ist definitiv eine simple Sprache
  • Guy Steeles Growing a Language ist ein Vortrag, der zeigt, wie Sprachen aus Primitives aufgebaut werden
    • Das Lisp-Zitat, wonach eine nahtlose größere Sprache entsteht, wenn neue, vom Benutzer definierte Wörter wie Primitives aussehen und Primitives wie vom Benutzer definierte Wörter, lässt sich auch auf Forth anwenden
  • Die abschließende Aufforderung lautet, die perfekte Programmiersprache für sich selbst zu bauen

1 Kommentare

 
GN⁺ 2023-07-18
Hacker-News-Kommentare
  • Als ich zum ersten Mal mit Forth in Berührung kam, dachte ich sofort, dass ich selbst eins bauen muss, und habe vor zwei Jahren in nur einer Woche MiniForth geschrieben
    Es war für den Blue Pill und das ursprüngliche Arduino gedacht, wurde aber als Cross-Compiler entwickelt, damit ich es auf dem Host testen konnte
    Ich war so vertieft, dass ich mich jeden Tag nach der Arbeit darauf freute, weiter daran herumzubasteln, und habe es in fünf Abenden unter der Woche plus einem Wochenende fertiggestellt; so viel Spaß hat das Bauen von Forth gemacht
    Ich kann diesen Prozess nur nachdrücklich empfehlen; ein ähnliches Aha-Erlebnis hatte ich nur, als ich zum ersten Mal Lisp-Makros gesehen habe (https://www.thanassis.space/score4.html#lisp)
    • Genau. In meinem Einführungskurs zur Rechnerarchitektur mussten wir als freies Abschlussprojekt etwas für den LC-3 bauen, und weil ich vorher mit dem Minecraft-Mod RedPower 2 schon ein wenig mit Forth herumgespielt hatte, dachte ich, es wäre lustig, es selbst zu implementieren
      Das hat fast meine gesamte freie Zeit in diesem Semester verschlungen, und an einem Tag schaute ich erst auf die Uhr, als es schon wieder hell wurde, und merkte, dass ich die Nacht durchgemacht hatte
      Ich habe Forth im echten Leben nie praktisch eingesetzt, aber die Erfahrung, von Grund auf eines zu bauen, lässt sich kaum anders als beinahe religiös beschreiben
      Es fühlte sich an wie Fred Brooks’ reinste Destillation des Programmierens: dass Programmierer wie Dichter nur einen winzigen Schritt von den reinen Materialien des Denkens entfernt arbeiten, mit bloßer Vorstellungskraft Luftschlösser bauen und Programme eine Art reale Magie sind, bei der etwas auf dem Bildschirm lebendig wird, das es vorher nicht gab, wenn man den Zauberspruch richtig eintippt
    • Stimme völlig zu. Vor sehr langer Zeit habe ich einmal einen Forth-Compiler in ZX81 BASIC geschrieben
      Etwas, das 19 Sekunden brauchte, um 1000 Zahlen auf dem Bildschirm auszugeben, war danach praktisch sofort fertig
      Und ich habe noch eine große Lektion gelernt: Ich sah mir den erzeugten Maschinencode an und dachte, er sei perfekt und nicht weiter verbesserbar, kam aber am nächsten Tag zurück und machte ihn viel schneller
  • Man könnte sich fragen: „Wie soll es sich selbst schreiben? Heißt das nicht einfach nur, dass man Funktionen verwenden kann?“
    Bis zu einem gewissen Grad ja, aber Forth geht weiter, weil man neue Wörter definieren kann, die wie echte Bestandteile der Sprache selbst wirken
    Diese Wörter lassen sich wie eingebaute Operationen verwenden und können sogar ändern, wie die Sprache funktioniert
    Weil es eine erweiterbare Sprache ist, kann man auch neue Kontrollstrukturen definieren oder Wörter schreiben, die die Syntax verändern; diese Flexibilität ist in anderen Sprachen selten
    In diesem Sinn kann man Forth als eine Sprache sehen, die „sich selbst schreibt“, weil der Programmierer sie auf einer sehr grundlegenden Ebene anpassen und erweitern kann
    Das ähnelt auch dem Makrosystem von Lisp: So wie Lisp-Makros durch Transformationen zur Compile-Zeit neue Syntaxstrukturen und domänenspezifische Sprachen ermöglichen, erlauben Forth-Wörter Erweiterungen von Syntax und Funktionalität
    • Klingt nett, aber in fast 40 Jahren als professioneller Programmierer war nie die Syntax das Problem, sondern immer die Semantik
      Es mag Situationen geben, in denen A = B + C * D; besser ist, als jede aufzurufende Funktion einzeln hinzuschreiben, etwa bei Matrixmultiplikation, aber ich bin so einem Problem in der Praxis nie begegnet
      Ich frage mich, ob mir einfach die Vorstellungskraft fehlt, ob das nur in bestimmten Bereichen nützlich ist, in denen ich nie gearbeitet habe, ob die Forth-Syntax so karg ist, dass man sie erst erweitern muss, um vernünftig damit arbeiten zu können, oder ob Menschen ihre Sprache einfach gern anpassen, wie andere Autos tunen
      Ich verstehe nicht so recht, warum Leute sich wirklich dafür interessieren
  • Eines der derzeit interessantesten Forth-Projekte ist Dusk OS, ein in Forth geschriebenes 32-Bit-Betriebssystem mit eigenem C-Compiler, an dem auch mehrere Portierungen laufen
    https://duskos.org/
    • Über DuskOS selbst weiß ich nicht viel, aber historisch stimmt es schon, dass Forth so etwas wie „sein eigenes Betriebssystem“ war; verglichen mit dem, was moderne Leser unter einem Betriebssystem verstehen würden, war es allerdings ziemlich grob gestrickt
      Klar, was will man auf einer Maschine mit 8 KB RAM erwarten, aber historisch bot es zwar primitive Funktionen, hatte jedoch kaum Treiber und fast keines der meisten Abstraktionskonzepte
      Code wurde aus dem Quelltext geladen und war deshalb langsam, und Linking war eher so etwas wie das Laden von Blöcken in der richtigen Reihenfolge; um ein neues Programm zu laden, musste man zuerst das aktuelle entfernen
      Ich weiß nicht, ob das wirklich viel besser war als CP/M, das beim Beenden eines Programms oft einfach einen Kaltstart der Maschine machte, aber zumindest trennte CP/M BIOS und BDOS
    • Das hatte ich übersehen. Ich lese gerade „Beyond the Collapse“ und hatte schon das Gefühl, dass man mit Lisp-, APL/J- oder C-Kenntnissen auf Betriebssystemebene kaum an die Einfachheit von Forth herankommt
      Ich werde es mir spätestens vor dem nächsten Wochenende ansehen
  • Meine ersten Programmiersprachen waren x86-Assembler und Forth. Mein Vater war ganz auf Forth eingeschossen, und von ihm habe ich das Programmieren gelernt
    Als Teenager habe ich mehrere x86-Forth-Systeme für DOS gebaut, und das letzte war eine recht ausgereifte ANS-kompatible Implementierung namens „Third“: https://github.com/benhoyt/third
    Es ist ziemlich erstaunlich, dass man einen vollständig gebootstrappten Forth-Compiler inklusive Assembler in nur ein paar tausend Zeilen Code haben kann
    Vor Kurzem habe ich auch einen alten Artikel übertragen, den ich zusammen für das Magazin Forth Dimensions geschrieben hatte
    Die Ideen von Forth sind immer noch gut, aber Stack-Manipulation wird schnell unerquicklich und ist auch sehr schwer zu lesen
    Das sieht man an den Codebeispielen auf https://benhoyt.com/writings/forth-lookup-tables/, besonders bei Search-Table. Benennung ist schwierig, aber nichts zu benennen scheint noch schwieriger zu sein
    • Dass Stack-Manipulation unerquicklich wird, könnte daran liegen, dass du und ich eben nicht Chuck Moore sind
      Sein Code hat im Allgemeinen erstaunlich wenig Stack-Geschiebe. Zum Beispiel: http://www.merlintec.com/download/color.html
    • Ich habe nur kurz in den Third-Quellcode geschaut, aber er ist interessant
      Beim Bootstrapping wird kernel.com aufgerufen; ich frage mich, wie kernel.com gebaut wurde
  • Verwandter Chuck-Moore-Vortrag: „Programming a 144 Computer Chip to Minimize Power” (2013)

https://www.youtube.com/watch?v=0PclgBd6_Zs
So soll Forth ultrastromsparende Computer antreiben: GreenArrays liefert derzeit einen asynchronen 144-Core-Chip aus, der nur 7 pJ/inst benötigt.
Inaktive Kerne verbrauchen keinen Strom (100 nW), aktive Kerne laufen schnell mit 4 mW (666 Mips) und gehen dann wieder in den Leerlauf, während sie auf Kommunikation warten.

  • „Ich dachte immer, Größe und Geschwindigkeit seien nur für Amateure wichtig. Aber im modernen Kontext gibt es nur drei wichtige Parameter: Leistung, Leistung, Leistung.“
    --Chuck Moore
    https://youtu.be/0PclgBd6_Zs?t=389
  • Ich frage mich ernsthaft, ob solche Topologien in den kommenden Jahren wieder zurückkehren werden.
  • Ein großartiges Einsteigerbuch ist Starting Forth.
    Es enthält eine der ansprechendsten Illustrationen, die ich je in einem Lehrbuch gesehen habe.
    [0] https://www.forth.com/starting-forth/
  • Als vor langer Zeit OS/2 erschien, erzählte mir ein Freund, man könne „OS/2-Programme nicht in Assembler schreiben, man müsse sie in C schreiben“.
    Aus Trotz habe ich Forth/2 gebaut.
    Es war ein in Assembler geschriebener, direkt-threaded Native-Code-Forth-Compiler für OS/2; Brian Matthewson schrieb ein ausgezeichnetes Handbuch dafür, und wir gewannen einige Dutzend Nutzer.
    [1] https://sourceforge.net/projects/forth2/
  • Etwas anderes Thema, aber ich erinnere mich, die ursprüngliche Präsentation in Prototypform zu diesem Artikel gelesen zu haben.
    Im Wesentlichen war sie dieselbe wie der jetzige Text, aber mit viel weniger Text und mehr Lücken.
    Ich erwähne das, weil das Material auch in Bezug auf die zugrunde liegende Website-Technologie die Schönheit des Minimalismus zeigt.
    [0] http://ratfactor.com/forth/forth_talk_2023.html
    [1] http://ratfactor.com/minslides/
  • Ich finde es interessant, dass es auch in Rust einen Forth-Compiler gibt. Relevante Materialien stehen unter [1].
    Die Benutzung ist noch etwas unklar[2], aber er wurde hier schon einmal erwähnt[3], und die Implementierung wirkt solide.
    Es ist keine REPL-Forth-VM, aber eine beeindruckende VM-Implementierung.
    Wenn FORTH eine VM ist, dachte ich immer, es könnte die optimale Wahl sein, wenn man ein kleines, effizientes System braucht, das Streaming-Daten verwalten kann und dabei eine Performance nahe Bare Metal liefert.
    Dazu kommt, dass man nicht mit dem Betriebssystem ringen muss.
    Mir scheint, als würde das im Wesentlichen das tun, was FPGA tut, nur auf einer Standard-CPU.
    Ich stelle mir dabei allerdings ein spezialisiertes System vor, bei dem man nicht alle Treiber selbst schreiben muss, um es mit der benötigten Hardware zu verbinden.
    [1] https://docs.rs/rust-forth-compiler/latest/src/rust_forth_co...
    [2] https://docs.rs/fortraith/latest/fortraith/
    [3] https://news.ycombinator.com/item?id=23501474
  • Ich habe noch ein weiteres Forth selbst implementiert.
    Es versucht nicht, die ursprüngliche Idee möglichst originalgetreu zu kopieren, sondern funktioniert etwas anders.
    Da im Artikel gesagt wurde, man könne dort Forth entdecken, lasse ich auch meine Implementierung hier: https://github.com/loscoala/goforth
    Der größte Unterschied ist, dass in dieser Forth-Variante der Quelltext vollständig in Bytecode übersetzt wird und es keine Laufzeitumgebung im klassischen Forth-Sinn gibt.
    Deshalb lässt sich der Bytecode leicht nach C übersetzen.
    Ich verwende dieses Forth, um C-Code zu erzeugen, und bette diesen Code dann in andere Software ein.
    • So ein Ansatz kann sehr produktiv und clever sein, aber man sollte sich immer bewusst sein, dass solche mehrsprachigen Lösungen langfristig leicht zu Wartungsproblemen werden.
      Es gibt ein wirklich gutes Open-Source-Projekt, mit dem man Gehörbildung und Blattlesen trainieren kann; es ist in einer Sprache geschrieben, die der Autor selbst geschaffen hat, und diese Sprache kompiliert nach JavaScript.
      Der Aufwand, allein die Toolchain einzurichten, war so groß, dass ich mich trotz etlicher bekannter Bugs nicht dazu durchringen konnte, sie zu beheben.
      https://sightreading.training/
      https://github.com/leafo/sightreading.training
      Dieses Projekt ist in einer Sprache namens „Moonscript“ geschrieben: https://github.com/leafo/moonscript
      Moonscript kompiliert nach Lua, und Lua kompiliert nach JS.
      Wahnsinn. Wundervoller Wahnsinn zwar, aber trotzdem hat es mich davon abgehalten, ein Mitwirkender zu werden.