from .trinary import * class Machine: def run(self, program): """Run Malbolge code passed as a string.""" #Accumulator self.a = trin(0) #Registers self.d = trinlist() self.c = trinlist() #Pointers self.pointer_c = trin(0) self.pointer_d = trin(0) statements = { "j": self.__swap_d, "i": self.__swap_c, "*": self.__rotate, "p": self.__crazy, "<": self.__read, "/": self.__print, "v": self.__exit, "o": self.__nop } #Check max lenght if len(program) > 3 ** 10: raise MemoryError("Out of memory. 3^10 words limit exceeded.") #Copy the program in register c for index, word in enumerate(program): if word not in ("\n", " "): if trinord(word) not in range(32, 127): raise SyntaxError("Invalid character:'%c' a %d." % (word, index)) else: self.c[index] = trinord(word) #Program execution while self.pointer_c < len(program): #Calculate current instruction statement = self.__calculate_statement(trinchr(self.c[self.pointer_c])) try: statements[statement]() except KeyError: statements["o"]() #Operations for each statement self.c[self.pointer_c] -= 33 self.__translate() self.pointer_c += 1 self.pointer_d += 1 def __calculate_statement(self, character): """ Calculates the instruction to be executed based on the character in the pointer. """ table = "+b(29e*j1VMEKLyC})8&m#~W>qxdRp0wkr \ Uo[D7,XTcA\"lI.v%{gJh4G\-=O@5`_3i< \ ?Z';FNQuY]szf$!BS/|t:Pn6^Ha" statement = (trinord(character) - 33 + self.pointer_c) % 94 return table[statement.decimal] def __translate(self): """ Write the statement in the code register following the conversion table. """ trans = str.maketrans( '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMN \ OPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~', '5z]&gqtyfr$(we4{WP)H-Zn,[%\\3dL+Q;>U!pJS72FhOA1 \ CB6v^=I_0/8|jsb9m<.TVac`uY*MK\'X~xDl}REokN:#?G"i@' ) statement = str.translate(trinchr(self.c[self.pointer_c]), trans) self.c[self.pointer_c] = trinord(statement) #Statements def __swap_d(self): """ Malbolge statement "j" Assign the data pointer the value it points to. """ self.pointer_d = self.d[self.pointer_d] def __swap_c(self): """ Malbolge statement "i" Assign to the code pointer the value pointed by the data pointer. """ self.pointer_c = self.d[self.pointer_d] def __rotate(self): """ Malbolge statement "*" Rotate the word pointed by the pointer by a trit to the right. """ self.d[self.pointer_d] = trin(self.a[-1] + self.a[0:-1]) def __crazy(self): """ Malbolge statement "p" Performs the operation crazy with the value in the accumulator and the value pointed by the data pointer. Then stores the result in the accumulator and log data. """ operation = [[1, 0, 0], [1, 0, 2], [2, 2, 1]] result = [] for i, j in zip(self.a, self.d[self.pointer_d]): result += operation[i][j], self.d[self.pointer_d] = trin(result) self.a = trin(result) def __read(self): """ Malbolge statement "<" Reads a character from stdin and stores it in the accumulator. """ character = input() if len(character) > 1: raise TypeError("Expected a character: read a string.") elif len(character) == 0: raise TypeError("Expected a character: read an empty string.") else: self.a = trinord(character) def __print(self): """ Malbolge statement "/" Print the character present in the accumulator. """ print(trinchr(self.a), end="") def __exit(self): """ Malbolge statement "v" Terminate the program. """ exit() def __nop(self): """ Malbolge statement "o" Performs the nop operation. """ pass