Quand j'ai regardé Twitter, il y avait une réponse comme "Pouvez-vous dire la même chose avec Malbolge?" En réponse à la déclaration "Si vous utilisez un langage de programmation, vous pouvez faire autre chose". J'étais un élève superficiel et j'ai demandé "Qu'est-ce que Malbolge?", Mais c'était une spécification de langage très puissante.
J'ai aussi marmonné le type "Si vous en faites un" ci-dessus, mais je suis désolé d'être une grenouille.
En regardant les spécifications du langage, je n'avais pas envie d'écrire le code moi-même, mais j'ai réalisé que la quantité d'implémentation ne serait pas si grande s'il s'agissait d'un interpréteur, alors je l'ai fait.
Vérifiez l'environnement ci-dessous. Je ne sais pas si ça marche ailleurs ... je suis désolé ...
S'il s'agit de pedia, les spécifications sont également décrites ci-dessous s'il s'agit de l'anglais.
Après cela, l'article suivant de Robert (id: Robe) a été très utile. Merci beaucoup.
https://robe.hatenablog.jp/entry/20060824/1156353550
Comme vous pouvez le voir sur ce qui précède, il est très difficile d'écrire ... ou y a-t-il quelqu'un qui peut écrire avec un crayon? Vous pouvez voir la difficulté en regardant Hello World (ci-dessous) posté sur pedia.
(=<`:9876Z4321UT.-Q+*)M'&%$H"!~}|Bzy?=|{z]KwZY44Eq0/{mlk**
hKs_dG5[m_BA{?-Y;;Vb'rR5431M}/.zHGwEDCBA@98\6543W10/.R,+O<
Personnellement, j'avais l'impression qu'il s'agissait d'un CPU virtuel plutôt que d'un langage. En gros les fonctionnalités que j'ai comprises.
En bref, c'est comme écrire en assembleur ou en langage machine avec du code obscurci.
Si vous le faites sur un Mac, la page suivante de Takaaki Yamamoto | Kazuaki Yamamoto vous sera très utile. Merci beaucoup.
https://blog.monophile.net/posts/20150118_malbolge_hello.html
La source de l'interpréteur (langage C) est la suivante.
http://www.lscheffer.com/malbolge_interp.html
C'est un bulletin lors de l'exécution sur Mac.
La création d'un interpréteur est beaucoup plus facile que la création d'un programme car le nombre d'instructions est petit et la valeur de mémoire maximale n'est pas un gros problème.
Donc je l'ai fait à peu près avec Python.
** Bien sûr, ce n'est pas parfait selon les spécifications, alors soyez prudent. Je pense qu'il y a un bug quelque part. ** **
#!/usr/bin/env python
# coding: utf-8
#
# malbolge_test.Écrit comme py
#
import sys
import hexdump
class MalbolgeInterpreterModoki:
"""
Interprète Malbolge (Modoki)
→ Veuillez me pardonner car je n'ai pas confirmé l'opération détaillée!
"""
def __init__(self, debug_mode):
"""
Initialisation
"""
self.debug_mode = debug_mode
self.OP_INDEX_CODE = 0
self.OP_INDEX_FUNC = 1
#Répartition du code (instruction) converti par xlat1
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]
]
#En regardant le code d'origine, il semble qu'un mot soit composé de 10 chiffres décimaux?
self.BASE3_DIGITS = 10
#Taille de la mémoire (pas d'octets, de mots-unsigned short-)
self.MEMORY_SIZE = 59049
#xlat1 est[C]C'est une table de conversion utilisée lors de la prise du code d'instruction.
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"
#Après avoir exécuté xlat2[C]Il s'agit d'une table de conversion utilisée pour réécrire le contenu de.
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):
"""
Initialisation des registres et de la mémoire (et des variables associées)
Cela ressemble à du BSS, mais cela n'a pas beaucoup de sens car il sera bientôt rempli ...
"""
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):
"""
Enregistrer l'affichage. Veuillez l'utiliser si nécessaire pour le débogage.
"""
print (self.seq, ": A=", self.A, "C=", self.C, "D=", self.D)
def dump_memory(self, max):
"""
Vidage de la mémoire. Veuillez l'utiliser si nécessaire pour le débogage.
# Cela peut être difficile sans adresse (;^ω^)
"""
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 effectue l'arithmétique ternaire, vous devez donc créer un nombre ternaire.
Cela fait d'un nombre décimal un nombre ternaire. Je fais la pire méthode de conversion (transpiration)
"""
#Tout d'abord, extrayez chaque chiffre des données d'origine.
digits = []
while True:
digits.append(data % 3)
if data <= 2:
break
data = int(data / 3)
#Puisque les chiffres sont fixes dans Malbolge, le reste est rempli de 0.
remain = self.BASE3_DIGITS - len(digits)
for i in range(0, remain):
digits.append(0)
return digits
def from_base3(self, digits):
"""
Malbolge effectue l'arithmétique ternaire, vous devez donc créer un nombre ternaire.
Cela transforme un nombre ternaire en un nombre décimal. Je fais la pire méthode de conversion (transpiration)
"""
#Exemple: 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):
"""
Traitement arithmétique de Malbolge. Calcule deux nombres ternaires et génère un nombre ternaire
Le calcul suivant est effectué pour chaque chiffre. Puisque le nombre de chiffres est fixe, vous pouvez le décrire avec cela
x/y 0 1 2
----------------
0 1 0 0
1 1 0 2
2 2 2 1
Exemple: fou(x=10, y=12) =12 (5 en décimal car c'est un nombre ternaire)
"""
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):
"""
Instruction MOV 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):
"""
Instruction JUMP 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):
"""
Commande de décalage vers la droite rotation_right [D]; A=D;
"""
ref_D = self.memory[self.D]
#Le décalage à droite réduit d'un chiffre (123 en décimal)/10 ->Comme 12)
result = int(ref_D / 3)
#Déplacez le contenu du chiffre le moins significatif vers le chiffre le plus significatif (123 pour la suite ci-dessus)->Sentiment d'en faire 312)
#19683 est un numéro ternaire 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):
"""
Commande arithmétique[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):
"""
Impression de sortie de caractère unique A;
Je suis désolé, c'est difficile à traiter, donc je vais casser chaque personnage m(__)m
"""
#Si vous regardez le code original, laissez-moi le diffuser
#Il semble que ce soit correct de sortir
#(S'agit-il d'une référence lors de la création d'une chaîne de caractères?)
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):
"""
Entrée d'entrée de caractère unique A
Je suis désolé, c'est difficile à traiter<enter>Est nécessaire m(__)m
@ :nouvelle ligne
# :Arrêt du système (géré comme une commande spéciale interne)
"""
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):
"""
Fin fin;
Le programme se termine ici.
"""
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):
"""
Exécute le traitement en fonction du code d'instruction
Chaque code d'instruction et son traitement sont auto.op_Parce que je l'ai listé dans le tableau
Mon travail est de comparer et de sauter
"""
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):
"""
Dans Malbolge, C et D sont définis une fois que chaque processus est terminé.+1
Lorsqu'il atteint la fin de la mémoire, il revient au début.
"""
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):
"""
Exécute une seule instruction.
Si vous voulez faire quelque chose de bien avec l'exécution des étapes
Cela peut être pratique.
"""
#Dans Malbolge le code en mémoire
#Je ne le fais pas simplement.
#Table convertie comme suit
#Utilisez le code.
#En d'autres termes, soyez conscient de cela
#Il semble que vous ayez besoin d'écrire une instruction.
ref_C = self.memory[self.C]
t_index = (ref_C - 33 + self.C) % 94
op_code = ord(self.xlat1[t_index])
#Exécutez l'instruction
self.execute_opcode(op_code)
#Après avoir exécuté l'instruction, la mémoire sera réécrite.
#Vous devez en être conscient lors de l'écriture d'opérations de mémoire
#Je ne pense pas que cela devrait être fait.
ref_C = self.memory[self.C]
self.memory[self.C] = ord(self.xlat2[ref_C - 33])
self.inc_regs()
def execute(self):
"""
Exécutez le programme.
Vous pouvez soit obtenir une fin, soit mourir d'un bug
(Oh, vous pouvez quitter avec # après l'entrée)
"""
while True:
self.execute_1step()
def is_this_valid_code(self, i, b):
"""
Vérification grammaticale simple
valid_Vérifiez s'il ne s'agit pas des instructions de la liste.
Si cela ne fonctionne pas, il se terminera.
"""
#NG sauf pour les commandes suivantes (commandes?).
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):
"""
Extrayez le programme en mémoire.
"""
#Initialisation
self.cpu_reset()
cnt = 0
#Chargement du code
with open(path, "rb") as f:
data = f.read()
for b in data:
#Ignorer les sauts d'espace
if b == 0x20 or b == 0x0d or b == 0x0a:
continue
#Vérification grammaticale simple. Si ça ne marche pas, quittez
self.is_this_valid_code(cnt, b)
#Ecrire le programme en mémoire
#
#Le modèle de mémoire de Malbolge
#C'est court non signé
#Le programme est un caractère non signé.
#Qu'est-ce que tu dis
# memory(0) <- code(0)
# memory(1) <-Mouche
# memory(2) <- code(1)
# memory(3) <-Mouche
#ça ira. Cela semble inutile s'il est emballé
#Puisqu'il s'agit de Python, je viens de le mettre dans un tableau ...
self.memory[cnt] = b
cnt += 1
#En langage C, le reste de la mémoire doit être rempli de 0.
#Malbolge ne l'a pas permis, comme ça
#Vous devez calculer Crazy et le mettre.
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__":
#Vérification des arguments
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)
#Définir la présence ou l'absence du mode débogage et le fichier programme à partir de l'argument
debug = False
path = sys.argv[1]
if len(sys.argv) == 3:
debug = True
path = sys.argv[2]
#Exécutez Malbolge
m = MalbolgeInterpreterModoki(debug)
m.load_code(path) #Extraire le programme en mémoire
m.execute() #Exécution du programme
Dans cet article, ce qui précède sera traité comme malbolge_test.py au moment de l'explication.
Il existe deux manières de l'utiliser.
C'est le mode à exécuter normalement. Cependant, les points suivants sont différents entre mon manque de capacité et mon omission (sueur).
Si vous pensez que c'est caché ici, j'aimerais que vous corrigiez la source (sueur)
Un exemple d'exécution est le suivant (hello_ma est un programme Hello world Malbolge)
python ./malbolge_test.py hello_ma <enter>
Il s'agit d'un mode dans lequel l'état d'exécution de chaque instruction peut être retracé en plus de ce qui précède. Cependant, veuillez noter qu'il sera imprimé sans bosse, donc il sera doublé.
De même, un exemple d'exécution. Ajoutez le débogage.
python ./malbolge_test.py debug hello_ma <enter>
Les opérations suivantes ont été confirmées. Pour le dire autrement, je ne fais que cela. ..
Merci à ceux qui sont pleins de compassion que vous pouvez voir même un putain d'interprète (genre) fait par une telle défaite. Si vous le regardez de la principale ci-dessous, je pense que vous pouvez le suivre dans un flux.
Au fait, je ne savais pas d'après les spécifications, mais parfois je le trouvais à partir du code de l'interpréteur.
En fait, c'est le sentiment que je voulais le plus faire. J'ai essayé de visualiser comment cette source compliquée et mystérieuse est réellement traitée.
Puisqu'il est long de tout faire, exécutez-le en mode débogage et réimprimez le journal jusqu'au milieu (jusqu'à "Hell").
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
Jusqu'à présent, il semble que je fais de mon mieux avec des calculs fous et en créant la chaîne de caractères souhaitée. Si vous allez à l'arrière, il semble que vous utilisez également la commande jump.
Je n'ai pas utilisé la commande de rotation. À propos, 99 bouteilles de bière ont également utilisé Rotate. Vous pouvez bien écrire ce programme, n'est-ce pas? J'ai juste du respect pour lui. En tant que niveau débutant, moi.
En fait, il y a des cas où j'étais accro au débogage. Il s'agit d'une "copie de l'entrée (auteur: Lou Scheffer)" dans le site de Rober. Réimprimez le code.
D'BA@?>=<;:9876543210/.-,+*)('&%$#"!~}|{zyxwvutsrqponmlkji
hgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/
.-,+*)('&%$#"!~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTS
RQPONMLKJIHGFEDC&_Suss Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo
Suss Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo
Suss Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo
Suss Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo
Suss Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo Soo
(Réimprimé à partir du site de Rober (URL ci-dessous))
Cela fonctionne avec l'interpréteur d'origine, mais lorsque je le fais avec mon interprète, j'obtiens l'erreur suivante:
Illegal opcode= "~"(org:239)
J'ai pensé que ça me ferait mal de toucher mon propre interprète à mi-chemin du niveau débutant, mais il semble que même l'interprète d'origine se comporte de manière inattendue.
J'ai modifié l'original comme suit. J'ai un contrôle de plage dans la fonction exec.
#if 1 /*Partie supplémentaire: essayez d'ajouter une vérification de plage*/
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++;
Lorsqu'il est exécuté avec ceci, c'est comme suit.
!!!!!!!!!!!!!!! 156 >= 95
En d'autres termes, il semble qu'il s'établisse en accédant à des données en dehors de la plage de la table de conversion appelée xlat2. Je me suis demandé ce qui se passerait dans ce cas.
Alors, donnons Malbolge lorsque le montage est pris, en disant: "Si vous faites un langage de programmation, le reste sera géré" (sourire amer).
Recommended Posts