Schreiben Sie einen Hühnerdolmetscher!

8

Sie müssen einen Dolmetscher für eine coole Sprache namens Huhn schreiben !

Sie sollten ein Chicken-Programm aus einer Datei, Standardeingaben, Programm- oder Funktionsargumenten oder was auch immer für Ihre Sprache am bequemsten ist, sowie aus Eingaben in das Programm lesen.

Sie sollten das Ergebnis der Interpretation des Programms gemäß der Chicken-Sprachspezifikation ausdrucken oder zurückgeben.

Weitere Beschreibung der Sprache .


Hühnchen-Programmübersicht

Chicken arbeitet mit einem einzigen Stapel, der sein gesamtes Speichermodell zusammensetzt. Während der Ausführung von Anweisungen werden vom Programm Werte aus dem Stapel verschoben und entfernt. Es gibt jedoch auch Anweisungen, mit denen das Programm andere Teile des Stapels nach Belieben ändern kann.

Der Stapel enthält drei Segmente:

  1. Die Register bei den Indizes 0 und 1. Index 0 ist eine Referenz auf den Stapel selbst, und Index 1 ist eine Referenz auf die Benutzereingabe. Wird meistens für Anweisung 6 verwendet (siehe unten).
  2. Der geladene Code: Für jede Codezeile befindet sich in diesem Segment eine Zelle, die die Anzahl der "Hühner" in der Zeile enthält. Dies wird am Ende mit einer 0 (Opcode zum Beenden des Programms) aufgefüllt.
  3. Der eigentliche Programmstapel, in dem Werte während der Programmausführung verschoben / verschoben werden. Beachten Sie, dass die Segmente nicht isoliert sind. Dies bedeutet, dass es möglich ist, selbstmodifizierenden Code zu erstellen oder Code aus diesem Segment des Stapelbereichs auszuführen.

Das Huhn ISA

Der Befehlssatz von Chicken basiert auf der Häufigkeit, mit der das Wort "Huhn" in jeder Programmzeile erscheint. Eine leere Zeile beendet das Programm und gibt den obersten Wert im Stapel aus.

Der Hühnchen-Befehlssatz nach Anzahl der "Hühnchen" pro Zeile:

  1. Schieben Sie die wörtliche Zeichenfolge "Huhn" auf den Stapel
  2. Fügen Sie die beiden obersten Stapelwerte als natürliche Zahlen hinzu und geben Sie das Ergebnis an.
  3. Subtrahieren Sie die beiden obersten Werte als natürliche Zahlen und geben Sie das Ergebnis ein.
  4. Multiplizieren Sie die beiden obersten Werte als natürliche Zahlen und geben Sie das Ergebnis an.
  5. Vergleichen Sie zwei Spitzenwerte für Gleichheit, drücken Sie 1, wenn sie gleich sind, und 0, wenn dies nicht der Fall ist.
  6. Sehen Sie sich die nächste Anweisung an, um festzustellen, von welcher Quelle geladen werden soll: 0 Ladevorgänge vom Stapel, 1 Ladevorgänge von Benutzereingaben. Die Oberseite des Stapels zeigt auf die Adresse / den Index, die bzw. der aus der angegebenen Quelle geladen werden soll. Laden Sie diesen Wert und schieben Sie ihn auf den Stapel. Da dies ein doppelt breiter Befehl ist, überspringt der Befehlszeiger den Befehl, der zum Bestimmen der Quelle verwendet wird.
  7. Die Oberseite des Stapels zeigt auf die Adresse / den Index, in der / dem gespeichert werden soll. Der darunter liegende Wert wird abgelegt und im angegebenen Index im Stapel gespeichert.
  8. Die Oberseite des Stapels ist ein relativer Versatz, zu dem gesprungen werden kann. Wenn der Wert darunter wahr ist, springt das Programm um den Offset.
  9. Interpretiert die Oberseite des Stapels als ASCII und drückt das entsprechende Zeichen.
  10. (10 + N) Schiebt die Literalzahl n-10 auf den Stapel.

Beispiel

Angenommen, das Programm ist:

chicken chicken chicken chicken chicken chicken chicken chicken chicken chicken chicken
chicken chicken chicken chicken chicken chicken
(an empty line)

(Ein Katzenprogramm. Beachten Sie, dass die leere Zeile erforderlich ist, da die vorhergehende Zeile 6 "Huhn" enthält.)

Eingabe für das Chicken-Programm

Chicken

Ausgabe

Chicken

Die Referenzimplementierung von Chicken.js .


Fehlererkennung

Der Interpreter sollte einen Fehler hinterlassen und beenden, wenn in der Quelle ein Wort vorhanden ist, das nicht "Huhn" ist.


Viel Glück!

Wert Tinte
quelle
3
Sie müssen die Sprachspezifikationen in die Frage kopieren. Fragen sollten nicht auf externen Links beruhen.
mbomb007
Warum machst du das nicht auch selbst?
1
Das ist deine Frage. Sie bestimmen die Spezifikationen.
mbomb007
5
Die Dateieingabe beschränkt diese Herausforderung auf bestimmte Sprachen. Zum Beispiel ist es unmöglich, eine Hühnerantwort zu erstellen, was Sie sicher enttäuschen werden.
Aaron

Antworten:

1

Ruby, 335 Bytes

Nimmt den Namen der Eingabedatei als Befehlszeilenargument und nimmt Benutzereingaben (für Anweisung Nr. 6) von STDIN entgegen.

Da Ruby "trueyy" (alles außer falseund nil) sich von Javascript "truety" (Ruby truey plus 0, leere Zeichenfolgen usw.) unterscheidet, kann es in einigen Fällen vorkommen, dass Programme, die auf einem JS-Interpreter einwandfrei funktionieren , in diesem Fall fehlschlagen wegen der Anweisung Nr. 8, z. B. wenn sie ""sich auf dem Stapel befindet. Ich habe jedoch den größten Fall behoben, der falsch ist 0.

Funktioniert mit dem Testprogramm und dem Hello World-Programm auf der Chicken-Website.

+(/^(#{c='chicken'}|\s)*$/m=~f=$<.read+"

")
s=[0,STDIN.read]+f.lines.map{|l|l.split.size};s[0]=s;i=1
s<<(s[i]<10?[->{c},->{x,y=s.pop 2;x+y},->{x,y=s.pop 2;x-y},->{s.pop*s.pop},->{s.pop==s.pop},->{s[s[i+=1]][s.pop]},->{s[s.pop]=s.pop;s.pop},->{l,k,j=s.pop 3;i+=j if k&&k!=0;l},->{s.pop.chr}][s[i]-1][]:s[i]-10)while s[i+=1]>0
$><<s.pop

Erläuterung

Der Interpreter startet sofort, indem er eine Regex-Übereinstimmung /^(chicken|\s)*$/mmit der gesamten Datei ( $<.read) ausführt , wodurch sichergestellt wird, dass die Datei nur chickenLeerzeichen enthält. In Ruby gibt dieser Operator den Index für die Übereinstimmung zurück oder nilwenn er nicht gefunden wurde.

Hier werden zwei Tricks zum Speichern von Bytes verwendet: Anstatt direkt abzugleichen chicken, wird der String-Ersetzungsoperator #{}stattdessen verwendet, um diesen String auch einer Variablen für später zuzuweisen (spart 1 Byte) und wenn der Inhalt der Datei zur Verarbeitung in einer Variablen gespeichert wird Es werden zwei Zeilenumbrüche angehängt, damit die linesFunktion später auf natürliche Weise ein Extra 0an das Ende des Befehlssatzes anhängen kann . (Zwei werden benötigt, da nachfolgende Zeilenumbrüche ignoriert werden, die für das Chicken-Programm erforderlich sind.)

Der verwendete Fehler ist NoMethodError: undefined method '+@' for nil:NilClass, dass das Regex-Match in Parens eingewickelt und ein vorangestellt wird +. Wenn die Datei mit dem Muster übereinstimmt, erhalten Sie +0, was 0normal ausgewertet wird und fortgesetzt wird.

Als nächstes wird der Stapel zusammengebaut. Die anfängliche Liste muss erstellt werden, bevor die Selbstreferenz auf den Stapel zugewiesen werden kann. Daher wird ein Platzhalter verwendet und dann ersetzt. Der Anweisungszeiger wird 1anstelle von gesetzt, 2da in Ruby keine Post-Inkrement-Operatoren vorhanden sind.

Schließlich wird der Lambda-Trick von @BassdropCumberwubwubwub verwendet, um zu bestimmen, was als nächstes auf den Stapel geschoben werden soll. Wenn eine Operation nichts auf den Stapel schiebt, gibt der Interpreter einfach einen zusätzlichen Wert ein, damit der Stapel gleich bleibt. (Dies spart Bytes gegenüber dem Hinzufügen einer Push-Operation zu jedem einzelnen Lambda.)

Ungolfed Code:

f = $<.read + "\n\n"
+(/^(chicken|\s)*$/m =~ f)
s = [0, STDIN.read] + f.lines.map{|l|l.split.size}
s[0] = s
i = 1

while s[i += 1] > 0
    if s[i] < 10
        s.push [
            ->{'chicken'},
            ->{
                x,y = s.pop 2
                x+y
                },
            ->{
                x,y = s.pop 2
                x-y
                },
            ->{s.pop*s.pop},
            ->{s.pop==s.pop},
            ->{s[s[i+=1]][s.pop]},
            ->{s[s.pop]=s.pop;s.pop},
            ->{
                l,k,j=s.pop 3
                i+=j if k&&k!=0
                l
                },
            ->{s.pop.chr}
        ][s[i] - 1][]
    else
        s.push(s[i] - 10)
    end
end

print s.pop
Wert Tinte
quelle
Eigentlich glaube ich nicht, dass ich das kurz machen kann. (+1)
4

Javascript ES6, 398 Bytes

Ich bin mir sicher, dass dies das mit Abstand längste Golfspiel ist, das ich je gemacht habe, aber mein Gehirn erkennt nichts anderes als chickenzu diesem Zeitpunkt.

(a,b)=>{for(c='chicken',s=[j=0,b,...A=a.split`
`.map(m=>m.split(c).length-1)],i=A.length+2;j<A.length;([_=>s[++i]=c,_=>s[--i]=s[i]+s[i+1],_=>s[--i]=s[i]-s[i+1],_=>s[--i]=s[i]*s[i+1],_=>s[--i]=s[i]==s[i+1],_=>s[i]=s[2+j++]?b[s[i]]:s[s[i]],_=>s[s[i--]]=s[i--],_=>j+=s[--i]?s[--i+2]:0,_=>s[i]=String.fromCharCode(s[i])][s[j+2]-1]||(_=>s[++i]=s[j+1]-10))(j++));return /[^chicken \n]\w/g.test(a)?0:s[i]}

Ich werde die Erklärung bearbeiten, wenn mein Gehirn wieder funktioniert. Hier ist eine etwas ungolfed Version für jetzt.
Gibt für alles, was nicht der Fall ist, einen Falsey-Wert (0) auschicken

(a,b)=>{
    for(c='chicken',s=[j=0,b,...A=a.split`
    `.map(m=>m.split(c).length-1)],i=A.length+2; // loop init
    j<A.length; // loop condition
    ( // everything else
        [
            _=>s[++i]=c,
            _=>s[--i]=s[i]+s[i+1],
            _=>s[--i]=s[i]-s[i+1],
            _=>s[--i]=s[i]*s[i+1],
            _=>s[--i]=s[i]==s[i+1],
            _=>s[i]=s[2+j++]?b[s[i]]:s[s[i]],
            _=>s[s[i--]]=s[i--],
            _=>j+=s[--i]?s[--i+2]:0,
            _=>s[i]=String.fromCharCode(s[i])
        ][s[j+2]-1]
        ||(_=>s[++i]=s[j+1]-10)
    )(j++)
);
return /[^chicken \n]\w/g.test(a)?0:s[i]}

Probieren Sie es hier aus

f=
  (a,b)=>{for(c='chicken',s=[j=0,b,...A=a.split`
`.map(m=>m.split(c).length-1)],i=A.length+2;j<A.length;([_=>s[++i]=c,_=>s[--i]=s[i]+s[i+1],_=>s[--i]=s[i]-s[i+1],_=>s[--i]=s[i]*s[i+1],_=>s[--i]=s[i]==s[i+1],_=>s[i]=s[2+j++]?b[s[i]]:s[s[i]],_=>s[s[i--]]=s[i--],_=>j+=s[--i]?s[--i+2]:0,_=>s[i]=String.fromCharCode(s[i])][s[j+2]-1]||(_=>s[++i]=s[j+1]-10))(j++));return /[^chicken \n]\w/g.test(a)?0:s[i]}

i.innerHTML = f(`chicken chicken chicken chicken chicken chicken chicken chicken chicken chicken chicken
chicken chicken chicken chicken chicken chicken
`, 'Hello world!')
<pre id=i>

Bassdrop Cumberwubwubwub
quelle
Lassen Sie mich auf weitere Antworten warten und herausfinden, wer der Gewinner ist.
Dies schlägt die "Fehlererkennung" fehl. Sie können dies tun, indem Sie if(!/^(chicken\s?)+$/.test(a))throw'There are any words except "chicken".';gleich zu Beginn Ihres Dolmetschers hinzufügen .
Ismael Miguel
@ Matthew, was denkst du darüber? Es gibt bestimmte Sprachen, die keinen Fehlertyp haben. Diese können stattdessen normalerweise einen Falsey-Wert ausgeben. Es ist ein bisschen vage im OP, also nahm ich an, dass das in Ordnung war.
Bassdrop Cumberwubwubwub
Sie können den Fehler ausgeben und ihnen mitteilen, dass etwas nicht stimmt.
1
@BassdropCumberwubwubwub Das OP bedeutete beispielsweise, eine Ausnahme auszulösen oder etwas auszugeben stderroder das Programm mit einem Code ungleich Null zu beenden. Etwas, das zeigt, dass etwas nicht stimmt. In Javascript können Sie eine Ausnahme auslösen, ein Fehlerobjekt zurückgeben, eine Warnung anzeigen, mit console.erro()oder Ähnlichem in die Konsole schreiben .
Ismael Miguel