Schreiben Sie auf der Grundlage eines Kommentars von George Edison zu dieser Frage den kleinsten selbstübersetzenden Dolmetscher.
- Sie können die Sprache Ihrer Wahl verwenden.
- Leere Sprachen zählen nicht. Ihr Programm muss mindestens zwei Zeichen lang sein.
- Das Programm muss nicht die gesamte Sprache interpretieren, sondern nur eine vollständige Teilmenge der Sprachfunktionen (die den Interpreter enthält).
- Quines zählen nicht.
- Verwenden Sie nicht die in Ihrer Sprache integrierte
eval
Funktion oder eine gleichwertige Funktion. Gleiches gilt fürapply
usw.
code-golf
interpreter
Hoa Long Tam
quelle
quelle
/usr/bin/cat
) was ist mit Turing-Vollständigkeit?sexp
Parsers.Antworten:
CI - 260
320 → 260: Schieben Sie einfache Zuordnungen von Zeichen zu Anweisungen und falten Sie sie dann um. Dies halbiert die Codegröße pro Fall (es gibt 18 Fälle), kostet jedoch 30 Zeichen, um das Falten durchzuführen.
Dies ist eine weitere von mir erstellte Sprache ( Basisinterpreter auf Gist ). Es ist einzigartig, dass die Sprache Codefragmente reifiziert. Das heißt, Befehlsfolgen in dieser stapelbasierten Sprache werden in gleicher Weise verwendet wie Datenstrukturen oder Abschlüsse in anderen Sprachen:
Der Interpreter erstellt ein Codefragment des gesamten Programms, bevor er es ausführt, sodass es auch als Compiler betrachtet werden kann. Aus diesem Grund führt das Stapeln des Interpreters nicht zu einem exponentiellen Laufzeitaufwand.
Der Interpreter leitet alle seine Operatoren direkt vom Host-Interpreter ab. Das Parsen wird jedoch von selbst durchgeführt, sodass der Großteil des Codes nur aus Sequenzen besteht, die Zeichen in ihre jeweiligen Codeliterale übersetzen. Dies ist nicht dasselbe wie die Verwendung
eval
, zeigt jedoch, wie abhängig eine Implementierung einer Programmiersprache von der Semantik ihrer Host-Sprache / Architektur ist.Sprach-Referenz:
Holen Sie sich den Dolmetscher hier
Blöcke
(
...)
Erstellen Sie einen "Block", der praktisch eine Liste von Anweisungen ohne Kontext ist. Intern könnte es sogar Maschinencode sein.
Block
$
Rufen Sie einen Block auf. Der Angerufene erhält den globalen Stapel, der den aufgerufenen Block enthält.
Wert
^
Heben Sie einen Wert an. Machen Sie daraus einen Block, der diesen Wert überträgt.
Beispiel :
Block1 Block2
&
Verbinden Sie zwei Blöcke und bilden Sie einen, der beide nacheinander ausführt.
Beispiel :
Stapelbearbeitung
n
c
Kopieren Sie den n-ten Wert des Stapels.
Beispiel :
n
p
Zupfe den n-ten Wert des Stapels (entferne ihn und bringe ihn nach vorne).
Beispiel :
n
d
Löschen Sie n Werte vom Stapel.
0d
ist ein No-Op.Beispiel :
Vergleichsoperatoren
ab (on_true) (on_false)
=
Teste ob a gleich b ist. Verbrauchen Sie alle Argumente außer dem ersten und rufen Sie on_true oder on_false auf. Wenn ein Argument Null ist und das andere einen anderen Typ hat, ist das Ergebnis falsch. Andernfalls müssen a und b ganze Zahlen sein.
Beispiel :
ab (on_true) (on_false)
<
Testen Sie, ob a kleiner als b ist. a und b müssen ganze Zahlen sein.
Beispiel :
ab (on_true) (on_false)
>
Testen Sie, ob a größer als b ist. a und b müssen ganze Zahlen sein.
Beispiel :
a lo hi (on_true) (on_false)
~
Testen Sie, ob lo <= a <= hi ist. a, lo und hi müssen ganze Zahlen sein.
Beispiel :
I / O
c
.
Setze das Zeichen c (verbrauche es vom Stapel).
,
Holen Sie sich einen Charakter und schieben Sie ihn auf den Stapel. Wenn das Dateiende erreicht ist, wird -1 gedrückt.
c
!
Unget einen Charakter. Genau wie bei ungetc in C ist nur ein Pushback zulässig.
Ganzzahlige Literale
'c
Drücken Sie den Buchstaben c.
[0-9] +
Geben Sie eine Dezimalzahl ein.
Arithmetik
+
-
ab
*
Addiere / subtrahiere / multipliziere zwei Zahlen.
Beispiel :
ab
/
ab
%
Division und Modul. Anders als in C runden sich diese gegen negative Unendlichkeit ab.
Sonstiges
Code
#
KommentarDer
#
Charakter kommentiert alles bis zum Ende der Zeile aus.)
Dient zum Beenden von Blöcken. Kann auch zum Beenden des gesamten Programms verwendet werden.
Alle anderen Zeichen werden ignoriert.
quelle
Binäre Lambda-Rechnung, 232 Bits (29 Bytes)
0101000110100000000101011000000000011110000101111110011110000101110011110000001111000010110110111001111100001111100001011110100111010010110011100001101100001011111000011111000011100110111101111100111101110110000110010001101000011010
Weitere Informationen finden Sie unter http://en.wikipedia.org/wiki/Binary_lambda_calculus#Lambda_encoding
quelle
Ich kann das nicht würdigen , aber ich dachte, ich würde dieses erstaunliche teilen:
Brainf *** (423)
quelle
BlockScript - 535
BlockScript ist eine einfache Spaghetti-Stack- basierte Sprache, die ich speziell für diese Herausforderung entwickelt habe. Der Basisinterpreter ist blockscript.c .
Beispielprogramm (druckt die ersten 15 Fibonacci-Zahlen):
Der Interpreter liest sowohl den Quellcode als auch die Programmeingabe von der Standardeingabe in dieser Reihenfolge. Dies bedeutet, dass Sie zum Ausführen eines Interpreters innerhalb eines Interpreters einfach Folgendes kopieren und einfügen:
Wie im Film Inception kann man nicht tiefer als drei Ebenen gehen. Es ist keine Frage der Zeit, sondern des Raums. BlockScript leckt den Speicher stark, und dies hängt davon ab, wie die Sprache selbst gestaltet ist.
Sprach-Referenz:
Holen Sie sich den Dolmetscher hier
In BlockScript ist der "Stapel" kein Array, das durch nachfolgende Operationen überschrieben wird, wie Sie es möglicherweise gewohnt sind. Es ist tatsächlich als unveränderliche verknüpfte Liste implementiert, und ein Stapel bleibt für die Dauer des Programms bestehen. Außerdem entfernt kein Operator (außer
@
) Werte aus dem Stapel. Stapeländerungen wirken sich jedoch nur auf den Block aus, in dem sie auftreten.Werteauswahl
a
durchz
Nimm den 0-25ten Gegenstand vom Stapel und lege ihn auf den Stapel.
a
bezieht sich auf den Kopf oder das zuletzt geschobene Objekt des Stapels.A
durchZ
Holen Sie sich das 0-25ste Element des aktuellen Frames und schieben Sie es auf den Stapel.
[
Öffnen Sie einen "Rahmen", um Elemente aus der Stapelreferenz (siehe unten) auf dem Stapelkopf auszuwählen.
[
erfordert keine Übereinstimmung]
, aber Frames haben einen lexikalischen Gültigkeitsbereich. In BlockScript wird "scope" durch geschweifte Klammern ({
...}
) bestimmt, die Blöcke bilden. Daher hat das Öffnen eines Frames innerhalb eines Blocks keine Auswirkung auf den Code außerhalb des Blocks.]
Schließen Sie das aktuelle Bild und kehren Sie zum vorherigen Bild zurück (falls vorhanden).
Blöcke
{
...}
Erstellen Sie einen "Block" und legen Sie ihn auf den Stapel. Innerhalb eines Blocks beginnt der Stapel an der Stelle, an der er sich vor dem Block befand, mit der Ausnahme, dass der Stapel des Aufrufers nach oben verschoben wird. Stacks sind in BlockScript persistent und unveränderlich, sodass Blöcke Closures sind. Die Redewendung
{[
bedeutet, einen Block zu öffnen und dann einen Rahmen zu öffnen, um mit der Auswahl der Argumente zu beginnen (Verwendung vonA
throughZ
). Der Rückgabewert eines Blocks ist der Kopf des Stapels, wenn er}
erreicht ist.Beispiel:
Dies wird gedruckt
123BCD123DCB123BCD123DCB…
. Die Kleinbuchstaben beziehen sich auf Stapelwerte, während sich die Großbuchstaben auf Argumente beziehen (da der Frame auf den Stapel des Aufrufers festgelegt ist).A!
Nimmt den Kopf des Aufrufers (der garantiert der aufgerufene Block ist) und ruft ihn auf. Wenn Sie sich fragen, warum es sichBCD
jedes Mal umkehrt , müssen SieB. C. D.
diese Argumente in umgekehrter Reihenfolge eingeben, bevor der Block sich selbst aufruft.!
Rufen Sie einen Block auf. Schieben Sie den Rückgabewert auf den Stapel.
Stapelreferenzen
&
Erstellen Sie eine Stapelreferenz und verschieben Sie sie in den Stapel. Stellen Sie sich dies als "Super-Nachteile" vor, da es effektiv jeden Gegenstand auf dem Stapel aufnimmt und daraus ein "Tupel" bildet. Die Redewendung
&[
bedeutet das, was auch immera
,b
,c
genannt , bevor sie kann nun mit zugegriffen werdenA
,B
,C
(für den Rest des Blockes oder bis]
festgestellt wird).Zum Teil, weil
&
mehr Werte erfasst werden, als normalerweise benötigt werden, verliert BlockScript von Entwurf an Speicher.@
Wechseln Sie zu dem Stapel, auf den die Stapelreferenz zeigt
a
. Dieser Operator ist ziemlich seltsam, aber der BlockScript-Selbstinterpreter verwendet ihn ein paarmal, um zu vermeiden, dass dieselben Argumente zweimal übergeben werden müssen. Die Auswirkungen@
(oder im Übrigen jede Stapeloperation) sind auf den Block beschränkt, in dem sie aufgerufen werden. Außerdem bleibt der Frame davon unberührt@
, sodass Sie mit dem Frame die Werte erfassen können, die Sie nach dem Umschalten der Stapel benötigen.Bedingter Ausdruck
?
<on true>:
<on false>Bedingter Ausdruck, genau wie der ternäre Operator in C. Das heißt, wenn
a
"wahr" ist (dh nicht gleich der ganzen Zahl Null ist), dann mache <on wahr> , andernfalls mache <auf falsch> .I / O
Hinweis: Die Ein- und Ausgabe erfolgt in UTF-8. Ein "Zeichen" ist eine Ganzzahl, die einem Unicode-Index entspricht.
,
Holen Sie sich das nächste Zeichen der Eingabe und schieben Sie es auf den Stapel. Wenn das Ende der Eingabe erreicht ist, drücken Sie stattdessen -1.
.
Geben Sie das Zeichen auf dem Kopf des Stapels aus.
Ganzzahl- / Zeichenliterale
Hinweis: Ganzzahlen und Zeichen sind in BlockScript identisch.
'c
Drücken Sie den Buchstaben c.
[0-9] +
Geben Sie eine Dezimalzahl ein.
Arithmetik
Diese Operatoren arbeiten nur mit ganzzahligen Werten.
+
Berechnen Sieb
+a
(drücke das Ergebnis, aber verwerfe keinen der beiden Werte).-
Berechnenb
-a
.*
Berechnenb
*a
./
Rechnenb
/a
(ganzzahlige Division; rundet gegen negative Unendlichkeit).%
Berechnen Sieb
%a
(ganzzahliger Modul; rundet gegen negative Unendlichkeit).Vergleichsoperatoren
Diese Operatoren arbeiten nur mit ganzzahligen Werten.
<
Wennb
kleiner ist alsa
, drücke 1, sonst drücke 0.>
=
Sonstiges
#
Kommentar zum Zeilenende;
quelle
Zozotez LISP : 414
Zeilenumbrüche, die hinzugefügt werden, um einen netten Block zu erhalten, werden nicht benötigt und nicht gezählt.
Theoretisch sollte es in der Lage sein, sich selbst auszuführen, aber da der ursprüngliche Interpreter eine BrainFuck- Binärdatei und selbst ein Interpreter ist, konnte ich nur jeden Teil testen. Wenn
(p p)
ich es mir selbst und einem einfachen Ausdruck gebe, denke ich, dass es mehr Zeit braucht als die 40 Minuten, auf die ich bisher gewartet habe, und ich benutze mein Fastenjitbf
, um es auszuführen, was (falsch) Perl Inline-C verwendet, um C-Code im laufenden Betrieb auszuführen.Es ist unmöglich, das gesamte Zozotez in Zozotez zu implementieren, da es keine Mittel zum
:
Mutieren der Nachteile enthält und (setq / define) diese benötigt, um die Bindungen zu aktualisieren. Ich habe auch kein explizites begin / progn- oder & rest-Argument, keine Makros und keine speziellen Druckargumente implementiert, da ich es nicht im Interpreter verwendet habe. Ich habep
(print) mit einbezogen, obwohl ich es nicht benutze, daher müssen Programme ihre Berechnungen genau wie der ursprüngliche Interpreter explizit ausgeben.Das gleiche ungolfed:
quelle
CHIQRSX9 + (wahrscheinlich nicht konkurrierend), 2 Bytes
In dieser HQ9 + -basierten Sprache ist es nicht möglich, einen selbstübersetzenden Interpreter zu schreiben, ohne
I
einen integrierten Interpreter zu verwenden, der STDIN verarbeitet.quelle
eval
, was für Ausdrücke steht, nicht für Programme.X
soll die Sprache Turing-vollständig machen (also Primzahlen berechnen können) und zwar implementierungsabhängig.X
das Programm zufällig und führt es aus, was bedeutet, dass man nicht mehr als einen Befehl verwenden kann, um Primzahlen deterministisch zu berechnen. Können Sie mir ein Beispiel für einen Interpreter geben, mit dem SieX
die von Ihnen angegebene Art und Weise verwenden können?Concurrent Filesystem Befunge 98 - 53 \ 18 Bytes (mit ziemlicher Sicherheit Betrug)
Voller 53-Byte-Interpreter ohne Einschränkungen (obwohl ich keine komplizierten Timing-Interaktionen getestet habe, die IP-Splitting und Wrapping beinhalten):
Liest Eingaben aus einer Datei mit dem Namen
a
und führt sie aus. In den Regeln ist nicht festgelegt, dass wir keinen selbstmodifizierenden Code verwenden können.18-Byte-Interpreter, der kein Wrapping zulässt (die IP-Adresse wird an einer Kante des Codes verschoben und beginnt an der gegenüberliegenden Kante):
quelle