Als ich mir Twitter ansah, gab es eine Antwort wie "Können Sie dasselbe mit Malbolge sagen?" Als Antwort auf die Aussage "Wenn Sie eine Programmiersprache verwenden, können Sie etwas dagegen tun." Ich war ein flacher Schüler und fragte "Was ist Malbolge?", Aber es war eine sehr mächtige Sprachspezifikation.
Ich habe auch den obigen Typ "Wenn du einen machst" gemurmelt, aber es tut mir leid, dass ich ein Frosch war.
Als ich mir die Sprachspezifikationen ansah, hatte ich keine Lust, den Code selbst zu schreiben, aber mir wurde klar, dass der Implementierungsaufwand als Interpreter nicht so groß sein würde, also habe ich ihn erstellt.
Überprüfen Sie die Umgebung unten. Ich weiß nicht, ob es woanders funktioniert ... Es tut mir leid ...
Wenn es sich um Pedia handelt, werden die Spezifikationen auch unten beschrieben, wenn es sich um Englisch handelt.
Danach war der folgende Artikel von Robert (id: Robe) sehr hilfreich. Vielen Dank.
https://robe.hatenablog.jp/entry/20060824/1156353550
Wie Sie oben sehen können, ist es sehr schwierig zu schreiben ... oder gibt es jemanden, der mit einem Bleistift schreiben kann? Sie können die Schwierigkeit anhand von Hello World (unten) auf pedia erkennen.
(=<`:9876Z4321UT.-Q+*)M'&%$H"!~}|Bzy?=|{z]KwZY44Eq0/{mlk**
hKs_dG5[m_BA{?-Y;;Vb'rR5431M}/.zHGwEDCBA@98\6543W10/.R,+O<
Persönlich hatte ich den Eindruck, dass es sich eher um eine virtuelle CPU als um eine Sprache handelt. Ungefähr die Funktionen, die ich verstanden habe.
Kurz gesagt, es ist wie das Schreiben in Assembler- oder Maschinensprache mit verschleiertem Code.
Wenn Sie dies auf einem Mac tun, ist die folgende Seite von Takaaki Yamamoto | Kazuaki Yamamoto sehr hilfreich. Vielen Dank.
https://blog.monophile.net/posts/20150118_malbolge_hello.html
Die Quelle des Interpreters (C-Sprache) ist wie folgt.
http://www.lscheffer.com/malbolge_interp.html
Es ist ein Bulletin, wenn es auf einem Mac ausgeführt wird.
Das Erstellen eines Interpreters ist viel einfacher als das Erstellen eines Programms, da die Anzahl der Anweisungen gering ist und der maximale Speicherwert keine große Rolle spielt.
Also habe ich es ungefähr mit Python geschafft.
** Natürlich ist es nicht perfekt gemäß den Spezifikationen, also seien Sie bitte vorsichtig. Ich denke, irgendwo gibt es einen Fehler. ** ** **
#!/usr/bin/env python
# coding: utf-8
#
# malbolge_test.Geschrieben als py
#
import sys
import hexdump
class MalbolgeInterpreterModoki:
"""
Malbolge Interpreter (Modoki)
→ Bitte verzeihen Sie mir, da ich die detaillierte Operation nicht bestätigt habe!
"""
def __init__(self, debug_mode):
"""
Initialisieren
"""
self.debug_mode = debug_mode
self.OP_INDEX_CODE = 0
self.OP_INDEX_FUNC = 1
#Aufschlüsselung des von xlat1 konvertierten Codes (Befehls)
self.op_table = [
[106, self.op_mod_d],
[105, self.op_jmp],
[42, self.op_rotate],
[112, self.op_crz],
[60, self.op_print],
[47, self.op_input],
[118, self.op_end],
[111, self.op_nop]
]
#Wenn man den Originalcode betrachtet, scheint es, als ob ein Wort 10 Dezimalstellen hat?
self.BASE3_DIGITS = 10
#Speichergröße (keine Bytes, Wörter-unsigned short-)
self.MEMORY_SIZE = 59049
#xlat1 ist[C]Es ist eine Konvertierungstabelle, die verwendet wird, wenn der Anweisungscode aus entnommen wird.
self.xlat1 = "+b(29e*j1VMEKLyC})8&m#~W>qxdRp0wkrUo[D7,XTcA\"lI"
self.xlat1 += ".v%{gJh4G\\-=O@5`_3i<?Z';FNQuY]szf$!BS/|t:Pn6^Ha"
#Nach dem Ausführen von xlat2[C]Dies ist eine Konvertierungstabelle, mit der der Inhalt von neu geschrieben wird.
self.xlat2 = "5z]&gqtyfr$(we4{WP)H-Zn,[%\\3dL+Q;>U!pJS72FhOA1C"
self.xlat2 += "B6v^=I_0/8|jsb9m<.TVac`uY*MK'X~xDl}REokN:#?G\"i@"
self.cpu_reset()
def cpu_reset(self):
"""
Initialisierung von Registern und Speicher (und verwandten Variablen)
Es sieht aus wie BSS, aber es macht nicht viel Sinn, weil es bald gefüllt wird ...
"""
self.memory = [0] * self.MEMORY_SIZE
self.A=int(0)
self.C=int(0)
self.D=int(0)
self.seq = 0
self.end = False
self.console = ""
def show_regs(self):
"""
Anzeige registrieren. Bitte verwenden Sie es gegebenenfalls zum Debuggen.
"""
print (self.seq, ": A=", self.A, "C=", self.C, "D=", self.D)
def dump_memory(self, max):
"""
Speicherauszug. Bitte verwenden Sie es gegebenenfalls zum Debuggen.
# Ohne Adresse kann es schwierig sein (;^ω^)
"""
print ("memory: size=", len(self.memory), " max=", max)
text = "["
i = 0
for data in self.memory:
text += hex(data) + " "
i += 1
if i == max:
break
text += "]"
print(text)
def to_base3(self, data):
"""
Malbolge führt eine ternäre Arithmetik durch, daher müssen Sie eine ternäre Zahl eingeben.
Dies macht eine Dezimalzahl zu einer ternären Zahl. Ich mache die schlechteste Konvertierungsmethode (Schweiß)
"""
#Extrahieren Sie zunächst jede Ziffer aus den Originaldaten.
digits = []
while True:
digits.append(data % 3)
if data <= 2:
break
data = int(data / 3)
#Da die Ziffern in Malbolge festgelegt sind, wird der Rest mit 0 gefüllt.
remain = self.BASE3_DIGITS - len(digits)
for i in range(0, remain):
digits.append(0)
return digits
def from_base3(self, digits):
"""
Malbolge führt eine ternäre Arithmetik durch, daher müssen Sie eine ternäre Zahl eingeben.
Dies verwandelt eine ternäre Zahl in eine Dezimalzahl. Ich mache die schlechteste Konvertierungsmethode (Schweiß)
"""
#Beispiel: 123-> 3 + 2 * 3 + 1 * 9 = 18
data = 0
base = 1
i = 0
for digit in digits:
data += digit * base
i += 1
if i == 1:
base = 3
else:
base *= 3
return data
def crazy(self, x, y):
"""
Malbolge arithmetische Verarbeitung. Berechnet zwei ternäre Zahlen und gibt eine ternäre Zahl aus
Die folgende Berechnung wird für jede Ziffer durchgeführt. Da die Anzahl der Ziffern fest ist, können Sie es damit beschreiben
x/y 0 1 2
----------------
0 1 0 0
1 1 0 2
2 2 2 1
Beispiel: verrückt(x=10, y=12) =12 (5 in Dezimalzahl, da es sich um eine ternäre Zahl handelt)
"""
crazy_table = [
[1, 0, 0],
[1, 0, 2],
[2, 2, 1]
]
digits_x = self.to_base3(x)
digits_y = self.to_base3(y)
result = []
data = 0
for i in range(0, self.BASE3_DIGITS):
data = crazy_table[digits_x[i]][digits_y[i]]
result.append(data)
return result
def op_mod_d(self):
"""
MOV-Anweisung D.= [D];
"""
ref_D = self.memory[self.D]
if self.debug_mode:
print (self.seq, "C=", self.C, ":106: D = [D]; # D=", self.D, "[D]=" , ref_D)
self.D = ref_D
def op_jmp(self):
"""
JUMP-Anweisung C.= [D]; jmp [D];
"""
ref_D = self.memory[self.D]
if self.debug_mode:
print (self.seq, "C=", self.C, ":105: C = *D; jmp [D]; # D=", self.D, "[D]=", ref_D)
self.C = ref_D
def op_rotate(self):
"""
Rechtsschaltbefehl drehen_right [D]; A=D;
"""
ref_D = self.memory[self.D]
#Rechtsverschiebung reduziert eine Ziffer (123 in Dezimalzahl)/10 ->Wie 12)
result = int(ref_D / 3)
#Verschieben Sie den Inhalt der niedrigstwertigen Ziffer auf die höchstwertige Ziffer (123, wenn es sich um eine Fortsetzung der obigen Ziffer handelt).->Gefühl, es zu schaffen 312)
#19683 ist eine ternäre Nummer 1000000000
result = result + (ref_D % 3) * 19683
if self.debug_mode:
print (self.seq, "C=", self.C, ": 42: rotate_right [D]; A=D; # D=", self.D, "[D]=", ref_D, "result=", result)
self.memory[self.D] = result
self.A = result
def op_crz(self):
"""
Rechenbefehl[D] = crazy(A, [D]); A=[D];
"""
ref_D = self.memory[self.D]
result_digits = self.crazy(ref_D, self.A)
result = self.from_base3(result_digits)
if self.debug_mode:
print (self.seq, "C=", self.C, ":112: [D] = crazy(A, [D]); A=[D]; # D=", self.D, "[D]=", ref_D, "A=", self.A, "result=", result)
self.memory[self.D] = result
self.A = result
def op_print(self):
"""
Einzelzeichenausgabedruck A.;
Es tut mir leid, es ist mühsam zu verarbeiten, also werde ich jedes Zeichen m brechen(__)m
"""
#Wenn Sie sich den Originalcode ansehen, lassen Sie mich ihn umsetzen
#Es scheint, dass die Ausgabe in Ordnung ist
#(Ist dies eine Referenz beim Erstellen einer Zeichenfolge?)
ascii = chr(self.A % 256)
if self.debug_mode:
print (self.seq, "C=", self.C, ": 60: print A; # put(\"", ascii ,"\") A=", self.A, ",", hex(self.A))
else:
print("put(\"", ascii ,"\")=", self.A)
self.console += ascii
def op_input(self):
"""
Eingabe einzelner Zeichen A.
Es tut mir leid, es ist mühsam zu verarbeiten<enter>Wird benötigt m(__)m
@ :Neue Zeile
# :Herunterfahren des Systems (als interner Sonderbefehl behandelt)
"""
print ("(m_o_m) Sorry, please input 1 char(@=cr,#=exit) and <enet>:")
text = input()
if text[0] == "@":
data = 0x0a
elif text[0] == "#":
print("exit this program.")
sys.exit(0)
else:
data = ord(text[0])
if self.debug_mode:
print (self.seq, "C=", self.C, ": 47: input A; # putc=", ord(text[0]), hex(data))
self.A = data
def op_end(self):
"""
Ende Ende;
Das Programm endet hier.
"""
if self.debug_mode:
print (self.seq, "C=", self.C, ":118: end;")
print ("end of program.")
print("console:")
print(self.console)
print("--------completed.")
sys.exit(0)
def op_nop(self):
"""
NOP nop
"""
if self.debug_mode:
print (self.seq, "C=", self.C, ":111: nop;")
return
def execute_opcode(self, op_code):
"""
Führt die Verarbeitung basierend auf dem Anweisungscode aus
Jeder Anweisungscode und seine Verarbeitung ist selbst.op_Weil ich es in der Tabelle aufgelistet habe
Meine Aufgabe ist es zu vergleichen und zu überspringen
"""
for op in self.op_table:
if op[self.OP_INDEX_CODE] == None or op[self.OP_INDEX_CODE] == op_code:
op[self.OP_INDEX_FUNC]()
return
if self.debug_mode:
print ("illegal op code ", op_code, " : -> nop.")
def inc_regs(self):
"""
In Malbolge werden C und D nach Abschluss jedes Vorgangs festgelegt.+1
Wenn es das Ende des Speichers erreicht, kehrt es zum Anfang zurück.
"""
if self.C == self.MEMORY_SIZE-1:
self.C = 0
else:
self.C += 1
if self.D == self.MEMORY_SIZE-1:
self.D = 0
else:
self.D += 1
self.seq += 1
def execute_1step(self):
"""
Führt nur eine Anweisung aus.
Wenn Sie mit der Schrittausführung etwas Gutes tun möchten
Dies kann zweckmäßig sein.
"""
#In Malbolge den Code im Speicher
#Ich mache es nicht einfach.
#Tabelle wie folgt konvertiert
#Verwenden Sie den Code.
#Mit anderen Worten, seien Sie sich dessen bewusst
#Es scheint, dass Sie eine Anweisung schreiben müssen.
ref_C = self.memory[self.C]
t_index = (ref_C - 33 + self.C) % 94
op_code = ord(self.xlat1[t_index])
#Führen Sie die Anweisung aus
self.execute_opcode(op_code)
#Nach dem Ausführen der Anweisung wird der Speicher neu geschrieben.
#Sie müssen sich dessen bewusst sein, wenn Sie Speicheroperationen schreiben
#Ich denke nicht, dass es getan werden sollte.
ref_C = self.memory[self.C]
self.memory[self.C] = ord(self.xlat2[ref_C - 33])
self.inc_regs()
def execute(self):
"""
Führen Sie das Programm aus.
Sie können entweder ein Ende bekommen oder an einem Fehler sterben
(Oh, Sie können mit # nach der Eingabe beenden)
"""
while True:
self.execute_1step()
def is_this_valid_code(self, i, b):
"""
Einfache Grammatikprüfung
valid_Überprüfen Sie, ob es sich nicht um die Anweisungen in der Liste handelt.
Wenn es nicht funktioniert, wird es beendet.
"""
#NG mit Ausnahme der folgenden Befehle (Befehle?).
valid_list = "ji*p</vo"
#( x - 33 + i ) % 94
t_index = (b - 33 + i) % 94
c = self.xlat1[t_index]
for valid in valid_list:
if valid == c:
return
print("Illegal opcode= \"" + c + "\"(org:"+ str(b) + ")")
sys.exit(1)
def load_code(self, path):
"""
Extrahieren Sie das Programm in den Speicher.
"""
#Initialisieren
self.cpu_reset()
cnt = 0
#Laden des Codes
with open(path, "rb") as f:
data = f.read()
for b in data:
#Leerzeichen ignorieren
if b == 0x20 or b == 0x0d or b == 0x0a:
continue
#Einfache Grammatikprüfung. Wenn es nicht funktioniert, beenden Sie
self.is_this_valid_code(cnt, b)
#Schreiben Sie das Programm in den Speicher
#
#Malbolges Gedächtnismodell
#Es ist nicht signiert kurz
#Das Programm ist vorzeichenloses Zeichen.
#Was sagst du
# memory(0) <- code(0)
# memory(1) <-Fliege
# memory(2) <- code(1)
# memory(3) <-Fliege
#Wird besorgt. Es scheint nutzlos zu sein, wenn es verpackt ist
#Da dies Python ist, habe ich es einfach in ein Array eingefügt ...
self.memory[cnt] = b
cnt += 1
#In der Sprache C sollte der Rest des Speichers mit 0 gefüllt sein.
#Malbolge erlaubte es nicht so
#Sie müssen Crazy berechnen und eingeben.
while cnt < self.MEMORY_SIZE:
x = self.memory[cnt - 2]
y = self.memory[cnt - 1]
self.memory[cnt] = self.from_base3(self.crazy(x,y))
cnt += 1
if __name__ == "__main__":
#Argumentprüfung
if len(sys.argv) < 2 or (len(sys.argv) == 3 and sys.argv[1] != "debug"):
print ("python malbolge_test.py (debug) <program file>")
sys.exit(1)
#Legen Sie das Vorhandensein oder Nichtvorhandensein des Debug-Modus und der Programmdatei anhand des Arguments fest
debug = False
path = sys.argv[1]
if len(sys.argv) == 3:
debug = True
path = sys.argv[2]
#Führen Sie Malbolge aus
m = MalbolgeInterpreterModoki(debug)
m.load_code(path) #Programm in den Speicher extrahieren
m.execute() #Programmausführung
In diesem Artikel wird das oben Gesagte zum Zeitpunkt der Erläuterung als malbolge_test.py behandelt.
Es gibt zwei Möglichkeiten, es zu verwenden.
Dies ist der Modus, der normal ausgeführt wird. Die folgenden Punkte unterscheiden sich jedoch zwischen meiner mangelnden Fähigkeit und meiner Unterlassung (Schweiß).
Wenn Sie denken, dass es hier versteckt ist, möchte ich, dass Sie die Quelle korrigieren (Schweiß)
Ein Ausführungsbeispiel lautet wie folgt (hello_ma ist ein Hello World Malbolge-Programm)
python ./malbolge_test.py hello_ma <enter>
Dies ist ein Modus, in dem der Ausführungsstatus jedes Befehls zusätzlich zu den oben genannten verfolgt werden kann. Bitte beachten Sie jedoch, dass es ohne Buckel gedruckt wird, sodass es verdoppelt wird.
Ebenso ein Ausführungsbeispiel. Debug hinzufügen.
python ./malbolge_test.py debug hello_ma <enter>
Die folgenden Vorgänge wurden bestätigt. Um es anders herum auszudrücken, ich mache das nur. ..
Vielen Dank an diejenigen, die voller Mitgefühl sind, dass Sie sogar einen verdammten Dolmetscher (wie) sehen können, der durch eine solche Niederlage entstanden ist. Wenn Sie es von unten betrachten, können Sie es in einem Fluss verfolgen.
Übrigens wusste ich es nicht aus den Spezifikationen, aber manchmal fand ich es aus dem Interpreter-Code.
Eigentlich ist dies das Gefühl, das ich am liebsten machen wollte. Ich habe versucht zu visualisieren, wie diese komplizierte und mysteriöse Quelle tatsächlich verarbeitet wird.
Da es lange dauert, alles zu tun, führen Sie es im Debug-Modus aus und drucken Sie das Protokoll bis zur Mitte (bis zur "Hölle") erneut.
0 C= 0 :106: D = [D]; # D= 0 [D]= 40
1 C= 1 :112: [D] = crazy(A, [D]); A=[D]; # D= 41 [D]= 93 A= 0 result= 29524
2 C= 2 :112: [D] = crazy(A, [D]); A=[D]; # D= 42 [D]= 75 A= 29524 result= 72
3 C= 3 : 60: print A; # put(" H ") A= 72 , 0x48
4 C= 4 :112: [D] = crazy(A, [D]); A=[D]; # D= 44 [D]= 90 A= 72 result= 29506
5 C= 5 :112: [D] = crazy(A, [D]); A=[D]; # D= 45 [D]= 89 A= 29506 result= 35
6 C= 6 :112: [D] = crazy(A, [D]); A=[D]; # D= 46 [D]= 52 A= 35 result= 29507
7 C= 7 :112: [D] = crazy(A, [D]); A=[D]; # D= 47 [D]= 52 A= 29507 result= 44
8 C= 8 :112: [D] = crazy(A, [D]); A=[D]; # D= 48 [D]= 69 A= 44 result= 29541
9 C= 9 : 60: print A; # put(" e ") A= 29541 , 0x7365
10 C= 10 :112: [D] = crazy(A, [D]); A=[D]; # D= 50 [D]= 48 A= 29541 result= 73
11 C= 11 :112: [D] = crazy(A, [D]); A=[D]; # D= 51 [D]= 47 A= 73 result= 29552
12 C= 12 :112: [D] = crazy(A, [D]); A=[D]; # D= 52 [D]= 123 A= 29552 result= 60
13 C= 13 :112: [D] = crazy(A, [D]); A=[D]; # D= 53 [D]= 109 A= 60 result= 29548
14 C= 14 : 60: print A; # put(" l ") A= 29548 , 0x736c
15 C= 15 : 60: print A; # put(" l ") A= 29548 , 0x736c
Bis zu diesem Punkt scheint es, dass ich mein Bestes mit verrückten Berechnungen gebe und die gewünschte Zeichenkette erstelle. Wenn Sie nach hinten gehen, scheinen Sie auch den Sprungbefehl zu verwenden.
Ich habe den Drehbefehl nicht verwendet. Übrigens verwendeten 99 Flaschen Bier auch Rotate. Sie können dieses Programm gut schreiben, richtig? Ich habe nur Respekt davor. Als Anfänger bin ich.
Tatsächlich gibt es Fälle, in denen ich vom Debuggen abhängig war. Es ist eine "Kopie der Eingabe (Autor: Lou Scheffer)" in Robers Website. Drucken Sie den Code erneut aus.
D'BA@?>=<;:9876543210/.-,+*)('&%$#"!~}|{zyxwvutsrqponmlkji
hgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/
.-,+*)('&%$#"!~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTS
RQPONMLKJIHGFEDC&_Süß Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo
Süß Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo
Süß Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo
Süß Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo
Süß Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo
(Nachdruck von Robers Website (URL unten))
Dies funktioniert mit dem ursprünglichen Interpreter, aber wenn ich es mit meinem Interpreter mache, erhalte ich den folgenden Fehler:
Illegal opcode= "~"(org:239)
Ich dachte, dass es weh tun würde, wenn ich meinen eigenen Dolmetscher in der Mitte des jungen Levels berühren würde, aber es scheint, dass sich selbst der ursprüngliche Dolmetscher unerwartet verhält.
Ich habe das Original wie folgt modifiziert. Ich habe eine Bereichsprüfung in der Exec-Funktion.
#if 1 /*Zusätzlicher Teil: Versuchen Sie, eine Bereichsprüfung hinzuzufügen*/
if (mem[c] -33 >= sizeof(xlat2))
{
printf("!!!!!!!!!!!!!!! %d >= %lu \n", mem[c] -33, sizeof(xlat2));
return;
}
#endif
mem[c] = xlat2[mem[c] - 33];
if ( c == 59048 ) c = 0; else c++;
if ( d == 59048 ) d = 0; else d++;
Wenn dies ausgeführt wird, ist es wie folgt.
!!!!!!!!!!!!!!! 156 >= 95
Mit anderen Worten, es scheint, dass es durch Zugriff auf Daten außerhalb des Bereichs der Konvertierungstabelle xlat2 hergestellt wird. Ich fragte mich, was in diesem Fall passieren würde.
Geben wir also Malbolge heraus, wenn das Reittier genommen wird, und sagen: "Wenn Sie eine Programmiersprache verwenden, wird der Rest verwaltet" (bitteres Lächeln).
Recommended Posts