Clem ist eine minimale stapelbasierte Programmiersprache mit erstklassigen Funktionen. Ihr Ziel ist es, einen Dolmetscher für die Clem-Sprache zu schreiben. Es sollte richtig alle Beispiele auszuführen , die in der Referenzimplementierung enthalten, die verfügbar ist hier .
- Wie üblich gelten Standardlücken .
- Der kleinste Eintrag nach Byte-Anzahl gewinnt.
Die Clem-Sprache
Clem ist eine stapelbasierte Programmiersprache mit erstklassigen Funktionen. Der beste Weg, um Clem zu lernen, besteht darin, den clem
Interpreter ohne Argumente auszuführen . Es wird im interaktiven Modus gestartet, sodass Sie mit den verfügbaren Befehlen spielen können. Geben Sie zum Ausführen der Beispielprogramme Folgendes ein: clem example.clm
Beispiel ist der Name des Programms. Dieses kurze Tutorial sollte ausreichen, um Ihnen den Einstieg zu erleichtern.
Es gibt zwei Hauptfunktionsklassen. Atomfunktionen und zusammengesetzte Funktionen. Zusammengesetzte Funktionen sind Listen, die aus anderen zusammengesetzten Funktionen und atomaren Funktionen bestehen. Beachten Sie, dass eine zusammengesetzte Funktion sich nicht selbst enthalten kann.
Atomfunktionen
Die erste Art der Atomfunktion ist die Konstante . Eine Konstante ist einfach ein ganzzahliger Wert. Zum Beispiel -10. Wenn der Interpreter auf eine Konstante stößt, schiebt er sie auf den Stapel. Lauf clem
jetzt. Geben Sie -10
an der Eingabeaufforderung ein. Das solltest du sehen
> -10
001: (-10)
>
Der Wert 001
beschreibt die Position der Funktion im Stapel und (-10)
ist die gerade eingegebene Konstante . Geben Sie nun +11
an der Eingabeaufforderung ein. Das solltest du sehen
> +11
002: (-10)
001: (11)
>
Beachten Sie, dass (-10)
die zweite Position im Stapel erreicht wurde und (11)
jetzt die erste belegt. Das ist die Natur eines Stapels! Sie werden feststellen, dass dies -
auch der Dekrementierungsbefehl ist. Wann immer -
oder +
vor einer Zahl, bezeichnen sie das Vorzeichen dieser Zahl und nicht den entsprechenden Befehl. Alle anderen atomaren Funktionen sind Befehle . Insgesamt gibt es 14:
@ Rotate the top three functions on the stack
# Pop the function on top of the stack and push it twice
$ Swap the top two functions on top of the stack
% Pop the function on top of the stack and throw it away
/ Pop a compound function. Split off the first function, push what's left,
then push the first function.
. Pop two functions, concatenate them and push the result
+ Pop a function. If its a constant then increment it. Push it
- Pop a function. If its a constant then decrement it. Push it
< Get a character from STDIN and push it to the stack. Pushes -1 on EOF.
> Pop a function and print its ASCII character if its a constant
c Pop a function and print its value if its a constant
w Pop a function from the stack. Peek at the top of the stack. While it is
a non-zero constant, execute the function.
Wenn Sie an der Eingabeaufforderung einen Befehl eingeben, wird der Befehl ausgeführt. Geben Sie #
an der Eingabeaufforderung (den Befehl duplicate) ein. Das solltest du sehen
> #
003: (-10)
002: (11)
001: (11)
>
Beachten Sie, dass (11) dupliziert wurde. Geben Sie nun %
an der Eingabeaufforderung den Befehl drop ein. Das solltest du sehen
> %
002: (-10)
001: (11)
>
Um einen Befehl in den Stapel zu verschieben, schließen Sie ihn einfach in Klammern ein. Geben Sie (-)
an der Eingabeaufforderung ein. Dadurch wird der Dekrementierungsoperator auf den Stapel verschoben. Das solltest du sehen
> (-)
003: (-10)
002: (11)
001: (-)
>
Zusammengesetzte Funktionen
Sie können auch mehrere atomare Funktionen in Klammern setzen, um eine zusammengesetzte Funktion zu bilden. Wenn Sie an der Eingabeaufforderung eine zusammengesetzte Funktion eingeben, wird diese auf den Stapel verschoben. Geben Sie ($+$)
an der Eingabeaufforderung ein. Das solltest du sehen
> ($+$)
004: (-10)
003: (11)
002: (-)
001: ($ + $)
>
Technisch gesehen ist alles auf dem Stapel eine zusammengesetzte Funktion. Einige der zusammengesetzten Funktionen auf dem Stapel bestehen jedoch aus einer einzelnen Atomfunktion (in diesem Fall werden wir sie der Einfachheit halber als Atomfunktionen betrachten). Bei der Bearbeitung zusammengesetzter Funktionen auf dem Stapel ist der .
Befehl (Verkettung) häufig hilfreich. Geben Sie .
jetzt ein. Das solltest du sehen
> .
003: (-10)
002: (11)
001: (- $ + $)
>
Beachten Sie, dass die erste und die zweite Funktion auf dem Stapel verkettet wurden und dass die zweite Funktion auf dem Stapel in der resultierenden Liste an erster Stelle steht. Um eine Funktion auszuführen, die sich auf dem Stapel befindet (egal ob atomar oder zusammengesetzt), müssen wir den w
Befehl (while) ausgeben . Der w
Befehl öffnet die erste Funktion auf dem Stapel und führt sie wiederholt aus, solange die zweite Funktion auf dem Stapel eine Konstante ungleich Null ist. Versuchen Sie vorherzusagen, was passieren wird, wenn wir tippen w
. Geben Sie nun ein w
. Das solltest du sehen
> w
002: (1)
001: (0)
>
Hast du das erwartet? Die zwei Zahlen, die oben auf dem Stapel sitzen, wurden addiert und ihre Summe bleibt erhalten. Versuchen wir es nochmal. Zuerst lassen wir die Null fallen und drücken eine 10 durch Eingabe %10
. Das solltest du sehen
> %10
002: (1)
001: (10)
>
Jetzt geben wir die gesamte Funktion in einem Schuss ein, aber %
am Ende fügen wir ein zusätzliches hinzu , um die Null loszuwerden. Geben Sie (-$+$)w%
an der Eingabeaufforderung ein. Das solltest du sehen
> (-$+$)w%
001: (11)
>
(Beachten Sie, dass dieser Algorithmus nur funktioniert, wenn die erste Konstante auf dem Stapel positiv ist.)
Saiten
Saiten sind ebenfalls vorhanden. Sie sind meistens syntaktischer Zucker, können aber sehr nützlich sein. Wenn der Interpreter auf eine Zeichenfolge stößt, schiebt er jedes Zeichen vom letzten zum ersten auf den Stapel. Geben Sie ein %
, um die 11 aus dem vorherigen Beispiel zu löschen. Geben Sie nun 0 10 "Hi!"
an der Eingabeaufforderung ein. Das 0
fügt einen NULL-Terminator ein und das 10
fügt ein neues Zeilenzeichen ein. Das solltest du sehen
> 0 10 "Hi!"
005: (0)
004: (10)
003: (33)
002: (105)
001: (72)
>
Geben Sie ein (>)w
, um Zeichen vom Stapel zu drucken, bis der NULL-Terminator angezeigt wird. Das solltest du sehen
> (>)w
Hi!
001: (0)
>
Schlussfolgerungen
Hoffentlich sollte dies ausreichen, um Ihnen den Einstieg in den Dolmetscher zu erleichtern. Das Sprachdesign sollte relativ einfach sein. Lassen Sie mich wissen, wenn etwas furchtbar unklar ist :) Einige Dinge wurden absichtlich vage gelassen: Werte müssen signiert sein und mindestens 16 Bit, der Stapel muss groß genug sein, um alle Referenzprogramme usw. auszuführen. Viele Details wurden nicht geschnitzt hier draußen, weil eine vollständige Sprachspezifikation unerschwinglich groß wäre (und ich habe noch keine geschrieben: P). Im Zweifelsfall ahmen Sie die Referenzimplementierung nach.
quelle
Antworten:
Haskell,
931921875Dies ist noch nicht vollständig Golf, aber es wird wahrscheinlich nie sein. Dennoch ist es bereits kürzer als alle anderen Lösungen.
Ich werde das bald mehr Golf spielen.Ich habe keine Lust mehr darauf zu spielen.hat wahrscheinlich ein paar subtile Fehler, weil ich nicht mit der C-Referenzimplementierung gespielt habe.
Diese Lösung verwendet den Typ
StateT [String] IO ()
zum Speichern eines "ausführbaren" Clem-Programms. Das meiste Programm ist ein Parser, der das "ausführbare Programm" analysiert.um diese Verwendung auszuführen
r "<insert clem program here>"
.quelle
Python,
16841281 ZeichenHabe alle grundlegenden Golf-Sachen erledigt. Es führt alle Beispielprogramme aus und stimmt die Ausgabe Zeichen für Zeichen ab.
Testen :
Sammeln Sie clemint.py , clemtest_data.py , clemtest.py und eine kompilierte
clem
Binärdatei in einem Verzeichnis und führen Sie sie ausclemtest.py
.Erweiterung :
Die ungolfedeste Version ist diese . Folgen Sie diesem.
S
ist der Hauptstapel. Jedes Element des Stapels ist eine 3-Liste, eine von:Für die Konstanten
f
ist eine Funktion, die die Konstante auf den Stapel schiebt. Für die atmoics,f
ist eine Funktion , die eine der Operationen ausführt (z-
,+
). Für die Verbindungenfs
ist eine Liste von Elementen.xec
führt ein Element aus. Wenn es sich um eine Konstante oder ein Atom handelt, wird nur die Funktion ausgeführt. Wenn es sich um eine Verbindung handelt und noch keine Rekursion stattgefunden hat, führt sie jede Funktion aus. So Ausführung(10 20 - 30)
wird jede der Funktionen ausführen10
,20
,-
, und30
, so dass10 19 30
auf dem Stapel. Wenn es eine Rekursion gegeben hat, wird die zusammengesetzte Funktion einfach auf den Stapel verschoben. Bei der Ausführung(10 20 (3 4) 30)
sollte das Ergebnis beispielsweise10 20 (3 4) 30
nicht sein10 20 3 4 30
.Das Verschachteln war etwas schwierig. Was machst du beim Ablesen
(1 (2 (3 4)))
? Die Lösung besteht darin, einen Stapel Stapel zu haben. Auf jeder Verschachtelungsebene wird ein neuer Stapel auf den Stapelstapel geschoben, und alle Push-Vorgänge werden auf diesen Stapel übertragen. Wenn eine Verschachtelung stattgefunden hat, werden atomare Funktionen verschoben anstatt ausgeführt. Wenn Sie also sehen10 20 (- 30) 40
,10
wird geschoben, dann20
wird ein neuer Stapel erstellt-
und30
auf den neuen Stapel geschoben. Er)
springt vom neuen Stapel ab, verwandelt ihn in einen Gegenstand und schiebt ihn eine Ebene tiefer auf den Stapel.endnest()
Griffe)
. Es war etwas knifflig, da es einen Sonderfall gibt, in dem nur ein Gegenstand geschoben wurde und wir zurück auf den Hauptstapel schieben. Das heißt,(10)
sollte die Konstante drücken10
, kein Verbund mit der einen Konstante, weil dann-
und+
nicht funktionieren. Ich bin mir nicht sicher, ob dies ein Prinzip ist, aber so funktioniert es ...Mein Interpreter ist ein zeichenweiser Prozessor - er erstellt keine Token -, daher war es etwas ärgerlich, mit Zahlen, Zeichenfolgen und Kommentaren umzugehen. Es gibt einen separaten Stapel
N
für eine aktuell verarbeitete Nummer, und jedes Mal, wenn ein Zeichen verarbeitet wird, das keine Nummer ist, muss ich anrufen, umendnum()
zu sehen, ob ich diese Nummer zuerst vervollständigen und auf den Stapel legen soll. Ob wir uns in einer Zeichenfolge oder einem Kommentar befinden, wird durch boolesche Variablen verfolgt. Wenn eine Zeichenfolge geschlossen ist, werden alle Innereien auf dem Stapel verschoben. Negative Zahlen erforderten ebenfalls eine spezielle Behandlung.Das war's für die Übersicht. Der Rest wurde die Umsetzung aller Einbauten, und sicherstellen , dass tiefe Kopien in tun
+
,-
und#
.quelle
C 837
Vielen Dank an @ceilingcat für die Suche nach einer viel besseren (und kürzeren) Version
Dies behandelt alles als einfache Zeichenfolgen - alle Stapelelemente sind Zeichenfolgen, sogar Konstanten sind Zeichenfolgen.
Probieren Sie es online aus!
Eine weniger Golfversion meines Originals (im Gegensatz zur Golfversion druckt diese den Stapel, wenn er endet, wenn er nicht leer ist und einen -e-Parameter verwendet, sodass Sie das Skript in der Befehlszeile angeben können, anstatt aus einer Datei zu lesen):
quelle