Interpretiere deine Sprache, aber nicht dich selbst?

21

Es gibt viele Herausforderungen, die "X interpretieren" sagen, wobei X eine einfache Sprache ist. Das ist meiner Meinung nach viel zu langweilig. Um allen zögernden Leuten im Internet etwas Interessantes zu bieten, können Sie versuchen, diese Herausforderung zu meistern:

Herausforderung

Wähle eine Sprache $LANG. $LANGkann eine beliebige vollständige Programmiersprache oder eine vollständige Teilmenge einer Programmiersprache sein. Beachten Sie, dass Sie ein Feature Ihrer Sprache nicht $LANGfür die Interpretation verwenden dürfen, da Ihre Einreichung auch in geschrieben sein muss $LANG.

Schreiben Sie einen Compiler / Interpreter für $LANGgeschrieben $LANG. Sie können alle Einrichtungen (einschließlich evalund Freunde) Ihrer Sprache verwenden, die verfügbar sind, um diesen Compiler zu schreiben. Um die Aufgabe herausfordernder zu gestalten, gibt es eine Einschränkung: Ihr Programm sollte in der Lage sein, alle gültigen Programme mit $LANGAusnahme Ihres Interpreters / Compilers selbst zu interpretieren / kompilieren . Wenn das zu interpretierende / zu kompilierende Programm Ihr Interpreter oder Compiler selbst ist (unabhängig vom Dateinamen), sollte Ihr Programm etwas tun, das nichts mit der Funktionalität eines Interpreters oder Compilers zu tun hat (z. B. Barfing oder Drucken Hello, world!).

Um diese Aufgabe noch komplexer zu gestalten, darf Ihr Programm beim Kompilieren oder Interpretieren keinen eigenen Quellcode lesen.

Spezifikationen

  • Diese Aufgabe ist Code Golf. Die Einsendung mit den wenigsten korrekten Zeichen gewinnt. Bei einem Unentschieden gewinnt die zuerst eingereichte Lösung.
  • Ihr Programm / Skript sollte das zu interpretierende Programm aus einer Datei lesen. Sie können den Pfad und den Namen fest codieren. Wenn die Datei gelesen wird, können Sie sie entweder in eine andere Datei kompilieren (die auf Ihrem System ausführbar sein muss) oder direkt ausführen. Wenn die $LANGDateilesefunktionen fehlen, können Sie den passenden Code auf eine andere Weise einlesen $LANG. Sie können möglicherweise nicht $LANGals Teilmenge einer anderen Sprache auswählen, aber die Funktionen zum Lesen von Dateien wurden entfernt.
  • Es gelten die üblichen Code-Golf-Regeln. Das heißt: Ihre persönliche Haustier-Sprache, die Sie nur erfunden haben, um diese Herausforderung zu lösen, ist verboten, wenn die Lösung damit trivial wird (z. B. die Definition eines Single-Char-Programms, das die Lösung genau implementiert). Der Missbrauch von Regeln wird gefördert.
FUZxxl
quelle
Dürfen wir dafür eine Sprache definieren, solange diese vollständig ist?
Cruncher
@Cruncher Ja, das bist du. Weitere Informationen finden Sie im letzten Aufzählungspunkt der technischen Daten.
FUZxxl

Antworten:

8

Rubin, 63

b=$<.read
t="b=$<.read\nt=%p\nb!=t%%t&&eval(b)"
b!=t%t&&eval(b)
Lowjacker
quelle
Antwort akzeptiert, solange es keine kleinere Lösung gibt.
FUZxxl
11

Perl, 89 Zeichen, kein Schummeln

$_=q($_=q(Q);s/Q/$_/;($q=join"",<>)eq$_?die:eval$q);s/Q/$_/;($q=join"",<>)eq$_?die:eval$q

Beachten Sie, dass dieser Code in Bezug auf "sich selbst" äußerst wählerisch ist. Insbesondere erkennt es sich selbst nicht, wenn sich in der Eingabe nachgestellte Zeilenumbrüche oder andere zusätzliche Leerzeichen befinden. Um es zu testen, speichern Sie es in einer Datei mit dem Namen (zum Beispiel) unquine.plund gehen Sie folgendermaßen vor:

$ perl unquine.pl unquine.pl
Died at unquine.pl line 1, <> line 1.

Denken Sie daran, dass die unquine.plDatei genau 89 Byte lang sein sollte, nicht mehr und nicht weniger. Wenn Sie es mit einem anderen Perl-Skript als Eingabe ausführen, wird das andere Skript wie folgt ausgeführt:

$ perl unquine.pl hello.pl
Hello, world!

Wie der Name vermuten lässt, basiert die Implementierung auf einem Quine - speziell diesem:

$_=q($_=q(Q);s/Q/$_/);s/Q/$_/

Dieser Code setzt $_sich selbst gleich; Der Rest des Programms (der natürlich im Inneren dupliziert werden muss $_) vergleicht $_nur die Eingabe, stirbt, wenn sie übereinstimmt, und wertet die Eingabe ansonsten aus.

Ilmari Karonen
quelle
Sie können diese ersetzen &&/ ;mit einem ternären (ein Zeichen aus, verdoppelt durch quining) Paar. Tolle Idee und Umsetzung!
JB
@JB: Guter Fang! Bis zu 89 Zeichen.
Ilmari Karonen
5

GolfScript, 30 Zeichen

{`".~"+"#{$<.read}".@=!{~}*}.~

Dieses Programm liest den Inhalt einer Datei, die in der Befehlszeile benannt ist, und interpretiert sie als GolfScript, wenn sie nicht genau dem obigen Code entspricht. Wenn die Eingabe genau dem obigen Code entspricht, wird sie einfach unverändert gedruckt (mit Ausnahme einer an das Ende angehängten neuen Zeile).

Dies ist eine recht einfache Anpassung dieses sich selbst identifizierenden Programms . Speziell:

  • { } ist ein Codeblock-Literal in GolfScript.
  • .~, angewendet auf einen Codeblock, dupliziert den Block und führt die Kopie aus.

Innerhalb des Codeblocks:

  • ` stringifiziert die Kopie des Codeblocks.
  • ".~"+Fügt die Zeichen hinzu .~und ergibt eine Zeichenfolge, die den Quellcode des Programms enthält.
  • "#{$<.read}"ist ein dokumentierter Hack , der die Ausführung von Ruby-Code in GolfScript ermöglicht. In diesem Fall wird die Ruby-Anweisung ausgeführt $<.read(die schamlos aus Lowjackers Ruby-Lösung gestohlen wurde ), mit der der Inhalt aller in der Befehlszeile angegebenen Dateien gelesen und zurückgegeben wird. Dieser Hack ist erforderlich, da GolfScript selbst keine expliziten Datei-E / A-Funktionen bietet.
  • .@ dupliziert und mischt die Elemente über dem Stapel, sodass der Stapel zwei Kopien des Dateiinhalts enthält, gefolgt vom Quellcode dieses Programms.
  • =! vergleicht die beiden obersten Elemente auf dem Stapel (dh den Dateiinhalt und die Quelle) und gibt 1 zurück, wenn sie unterschiedlich sind, und 0, wenn sie gleich sind.
  • {~}*wertet die verbleibende Kopie des Dateiinhaltes als GolfScript Code, aber nur , wenn das Ergebnis des Vergleichs 1 ist (Technisch gesehen führt sie den Codeblock {~}so oft durch die Anzahl auf dem Stapel als gegeben an , dh 0 oder 1 mal. Im Innern Der Block ~ist der GolfScript-Eval-Operator.)

Ps. Wenn das Lesen des auszuführenden Codes von stdin erlaubt ist, kann diese Herausforderung in 21 Zeichen gelöst werden , ohne dass Ruby eine Shell benötigt:

{`".~"+1$=!{""\~}*}.~

Dieses Programm liest eine Eingabezeichenfolge aus stdin und führt sie aus (mit einer leeren Eingabe), wenn sie nicht mit ihrer eigenen Quelle übereinstimmt. Wie im obigen Programm wird die Eingabe, die mit der Quelle übereinstimmt, einfach zurückgesendet.

Ilmari Karonen
quelle
Sieht gut aus, aber es scheint nicht so, als ob Sie Eingaben aus einer Datei lesen.
FUZxxl
Behoben, jetzt liest es aus einer Datei (genau) wie die Lösung von Lowjacker.
Ilmari Karonen
5

Python, 167 130 118 Bytes

Dies ist mein erster Versuch, Golf zu spielen. Es interpretiert jedes Programm außer sich selbst

Verbesserte Version:

i=open(raw_input()).read();q='i=open(raw_input()).read();q=%s;i==q%%repr(q)and a;exec(i)\n';i==q%repr(q)and a;exec(i)

Wenn es sich selbst holt, dann barfs mit:

Traceback (most recent call last):
  File "pygolf.py", line 1, in <module>
    i=open(raw_input()).read();q='i=open(raw_input()).read();q=%s;i==q%%repr(q)and a;exec(i)\n';i==q%repr(q)and a;exec(i)
NameError: name 'a' is not defined

Ich denke, diese Lösung funktioniert ziemlich genau so wie die von Ilmari Karonen. Die Grundidee ist ungefähr so:

input = read_some_file()
if input == some_quine()
    barf()
interpret(input)

Das Quine, das ich verwendete, basierte auf diesem:

(lambda x: x + repr((x,)))('(lambda x: x + repr((x,)))',)

Aber ich habe seitdem festgestellt, dass eine viel kürzere Quine ist:

q='q=%s;q%%repr(q)';q%repr(q)

Und das kann noch kürzer sein, wenn Sie die interaktive Python-Shell zulassen. In diesem Fall können Sie Folgendes tun:

'%s;_%%repr(_)';_%repr(_)

Da Python keine kurze Möglichkeit zum Abrufen von Befehlszeilenargumenten hat, habe ich mich für raw_input () entschieden (das ist immer noch ziemlich lang, aber nicht so lang wie

import sys;sys.argv[1]

Verwendung ist:

echo "foobar.py" | python quinterpretter.py

oder

python quinterpretter.py
<type filename and hit enter>

Ich habe eine kürzere Quine gefunden, aber hier ist meine alte Version (für die Nachwelt):

i=open(raw_input()).read();a if i==(lambda x,y:x+repr((x,y))+y)('i=open(raw_input()).read();a if i==(lambda x,y:x+repr((x,y))+y)', ' else 1;exec(i)\n') else 1;exec(i)
Gordon Bailey
quelle
Ersetze% s durch% r und entferne den Repr. % r bedeutet roh und es ist im Grunde dasselbe.
Loovjo
4

Ich kann mit Javascript nicht genau aus einer Datei lesen (ok, ich könnte, wenn ich das HTML5 FileReader-Ding benutze, aber das macht die Dinge viel komplizierter als ich brauche). Dies ist also eine Funktion, die ein Javascript-Programm als Zeichenfolge akzeptiert und ausführt.

Dies ist wahrscheinlich nicht so gut wie es sein könnte, aber hier ist es trotzdem:

Javascript, 252

function c(p){q='\"';s='\\';a="function c(p){q='\"';s='\\';a=%;a=a.slice(0,17)+s+a.slice(17,24)+a[23]+a.slice(24);a=q+a.replace('%',q+a+q)+q;alert(a);}";a=a.slice(0,17)+s+a.slice(17,24)+a[23]+a.slice(24);a=a.replace('%',q+a+q);alert(a);if(p!=a)eval(p)}

Lassen Sie mich wissen, ob jemand eine bessere Technik zum Bilden eines Quines in Javascript kennt.

Peter Olson
quelle
1
Ich habe unten eine 135-Zeichen-JS-Lösung veröffentlicht, die auf Ihrem Code und meiner Perl-Lösung basiert. +1 für die Inspiration!
Ilmari Karonen
2
read p<p;read c<c;[ "$p" = "$c" ]||. ./c

45 Zeichen von sh (POSIX-Shell). Der auszuführende Code muss in der Datei enthalten sein ./c.

Der Code für den Interpreter selbst muss sich in der Datei befinden ./p, also denke ich, dass ich irgendwie betrogen habe, obwohl die Herausforderung es nicht zu verbieten scheint. Oder würde dies meine "Sprache" von einer "absolut vollständigen Programmiersprache" disqualifizieren?

Mit einem Tool, das normalerweise eine externe ausführbare Datei ist, aber theoretisch in die Shell integriert werden kann, kann der Code verkürzt werden:

cmp -s p c||. ./c

Das sind 18 Zeichen, und das -sBit dient nur dazu, eine Zeile zu unterdrücken, die sonst immer für gültige (nicht selbst erstellte) Programme gedruckt würde.

Und dann können Sie immer eine Version der Shell-Sprache erstellen, die das oben Genannte mit einer präziseren Syntax ausführt.

Und dann können Sie immer ein Programm erstellen, wenn die Eingabe aus einem einzelnen '.' - oder zum Teufel, die leere Zeichenfolge-- wertet den Inhalt einer anderen Datei als normalen Code aus und nennt dies eine Programmiersprache. Die leere Zeichenfolge wäre also Ihre Lösung für die Herausforderung in der von Ihnen erstellten Sprache. In der Tat ist hier ein Dolmetscher für eine solche Sprache:

read code; if [ "$code" ]; then eval "$code"; else . ./othercode; fi

Unter Verwendung der Sprache, die das obige Skript interpretiert, ist die Lösung die leere Zeichenfolge. Und der Code-Ort muss nicht mehr fest codiert sein.

Problem?

TaylanUB
quelle
2
Die Herausforderung besagt jedoch, dass "Ihr Programm nicht die eigene Quelle lesen darf".
Ilmari Karonen
Darnit, ich habe einige Zeit verschwendet. Und ich sehe sogar, dass Sie keine Funktionen verwenden dürfen, die Sie weglassen werden. Dies würde gegen die Leerzeichenfolge-Funktion verstoßen. Dann wieder der Dolmetscher muss sein Weglassen / ändern Funktionalität , wenn der Code für den Compiler / Interpreter selbst unterschiedliche Verhalten in der neuen Sprache verursacht. Auf jeden Fall hat es mir Spaß gemacht, Trugschlüsse zu schreiben.
TaylanUB
@TaylanUB Nun, Sie müssen tatsächlich alle gültigen $ lang-Programme außer dem Interpreter selbst interpretieren.
FUZxxl
@FUZxxl Ja, die Sprache "sh + leere Zeichenfolge" ist ansonsten gleichbedeutend mit sh (wenn der Code nicht die leere Zeichenfolge ist), und das darin geschriebene leere Zeichenfolgeprogramm interpretiert auch sh-Code (der eingegeben werden muss ./othercode) und tut dies nichts, wenn der Code die leere Zeichenfolge ist. Ich hätte die Datei nicht ./othercode nennen sollen, das ist irreführend. Es ist nur der Code, den der Interpreter in der Sprache der leeren Zeichenfolgen interpretiert.
TaylanUB
2

JavaScript, 135 Zeichen

function c(p){q='function c(p){q=%27Q%27;p!=unescape(q).replace(/Q/,q)?eval(p):alert()}';p!=unescape(q).replace(/Q/,q)?eval(p):alert()}

Die JavaScript-Lösung von Peter Olson hat mich dazu inspiriert, meine Perl-Lösung auf JS zu portieren. Wie seine Lösung definiert dieser Code eine Funktion c, die eine Zeichenfolge akzeptiert, und bewertet sie, wenn sie nicht dem obigen Code entspricht.

Es dauerte eine Weile , um herauszufinden , eine gute Art und Weise mit dem Fehlen eines ausgewogenen String - Trennzeichen in JavaScript zu tun, bis ich was im Nachhinein ist die offensichtliche Lösung gefunden: unescape().

Praktischerweise enthält mein Code keine Backslashes oder doppelten Anführungszeichen, sodass er sicher in doppelten Anführungszeichen gespeichert werden kann. Dies macht es einfach zu testen:

e = "function c(p){q='function c(p){q=%27Q%27;p!=unescape(q).replace(/Q/,q)?eval(p):alert()}';p!=unescape(q).replace(/Q/,q)?eval(p):alert()}"
h = "alert('Hello, world!')"

eval(e)  // defines the function c()

c(h)     // evaluates h
c(e)     // does not evaluate e, alerts "undefined" instead
Ilmari Karonen
quelle
Sie könnten ersetzen alert()mit 0, um es tut nichts statt alarmieren undefinedund speichern 13 Zeichen.
Peter Olson
@PeterOlson: Ja, aber die Aufgabe besagt, dass "Ihr Programm etwas völlig Unabhängiges tun sollte", wenn es sich selbst erkennt. Ich interpretiere das so, dass es etwas bewirken soll - am besten etwas, das für den Benutzer sichtbar ist, würde ich annehmen. Außerdem gefällt es mir auf diese Weise einfach besser. :) (Ps. Yay, es schneit draußen! Der Winter ist endlich da!)
Ilmari Karonen
1
@Ilmari Nichts zu tun hat nichts mit der Interpretation von Javascript zu tun.
FUZxxl
Sie könnten p=>...stattdessen gehenfunction c(p)
FireCubez
2

Gemeiner Lisp, 59

#+~ #.(#:a)(defun L(p)(compile-file p))(push :~ *features*)
  • Kompilieren Sie in einem neuen Lisp REPL Ihre Datei (zB sbcl --load)
  • Sie haben jetzt eine Funktion L, mit der Sie Common-Lisp-Dateien kompilieren können
  • Wenn Sie jedoch anrufen (L <your file>), wird beim Lesen der Datei ein Fehler gemeldet .

Warum?

Weil Sie das :~Schlüsselwort zum ersten Mal in eingegeben haben *features*. Jetzt kennt Ihre Umgebung die ~Funktion, und das Reader-Makro #+wird nach Auswertung des ~ Funktionsausdrucks erfolgreich sein und das folgende Formular lesen, anstatt es wie beim ersten Mal zu überspringen. In Ihrer Datei bitte das folgende Formular ist #.(#:a), der fragt zu bewerten (#:a)bei Lesezeit und verwenden den resultierenden Wert als der Code eingelesen. Aber (#:a)ruft die Funktion mit dem uninterned Symbol zugeordnet #:a. Da #:aes nicht intern ist, ist es ein frisches Symbol, das an keine Funktion gebunden ist (dh nicht fboundp). Error.

Core-Dump
quelle
1

Schema, 48 oder 51 Zeichen

Schema ist eine Sprache mit vielen verschiedenen Implementierungen. Trotz Implementierungen, die dem neuesten RnRS entsprechen müssen, war der neueste Arbeitsstandard (R6RS) aufgrund seines Mangels an Minimalismus unpopulär. R7RS wird in Kürze als Abhilfe veröffentlicht, wobei die Sprache in 2 aufgeteilt wird. Die erste Sprache ist mächtig und minimalistisch und die zweite, eine Obermenge der ersten, soll Funktionserweiterungen für die Interoperabilität zwischen Implementierungen bereitstellen. Bis dahin stützen wir uns auf SRFIs (Scheme Requests For Implementation), die (bei Implementierung in der Host-Implementierung oder manuell (wie im Schema üblich)) eine Möglichkeit bieten, gemeinsame Aufgaben portabel auszuführen. Dies alles, um zu sagen, dass das erste Code-Snippet (51 Zeichen), obwohl es so portabel wie möglich bleibt, für den Zugriff auf Befehlszeilenargumente auf SRFI-22 (Ausführen von Schemaskripten unter UNIX) angewiesen ist:

(define(main x y)(case y(x => error)(else => load)))

oder besser lesbar:

(define (main current-file arg)
  (case arg
    [current-file => error]
    [else => load]))

Die zweite (48 Zeichen) ist ein dateiloses Mittel zur Interpretation, das sich nicht selbst auswerten kann (in einer Null-Umgebung):

(define(e)(write(eval(read)null-environment))(e))

oder besser lesbar:

(define (interpret)
  (write (eval (read) null-environment))
  (interpret))
Samuel Duclos
quelle
Ihr Code funktioniert nicht, wenn Sie Ihren Dolmetscher kopieren.
FUZxxl
1
Überlassen Sie es einer Schemaantwort, geschachtelte Klammern in der Prosa zu enthalten.
Cyoce
1

Groovy, 13 Bytes

{Eval.me(it)}

Dies sollte eine Teilmenge von Groovy interpretieren.

Testfälle:

p={Eval.me(it)}

p'''
    (0..37).each{println"1234567890JIHGFEDCBAKLMNOPQRST!?,.ZYXWVU"[it..it+2]}
'''

p'''
    {Eval.me(it)}
'''

Unglücklicherweise funktioniert es, obwohl es mit Sicherheit funktioniert, auf völlig interpretatorische Art und Weise und für ziemlich viele Eingaben.

Armand
quelle
In welcher Zeile liest du das zu interpretierende Programm? Ihr Code ist interessant, obwohl er für diese Aufgabe nicht gültig ist.
FUZxxl
Ich nehme an, der Fehler ist so etwas wie "Rekursionslimit überschritten"?
Ilmari Karonen