Partage
  • Partager sur Facebook
  • Partager sur Twitter

Interpreteur Brainfuck: problème

au niveau des boucles []

Sujet résolu
    9 août 2010 à 15:22:38

    Bonjour,

    J'ai tenté d'implémenter un interpréteur brainfuck depuis quelques temps, mais mon code n'arrive pas à faire des boucles.

    Voici mon code:
    #!/usr/bin/env python
    # -*- encoding: utf-8 -*-
    
    class RAM:
        def __init__(self):
            self.dict = {}
        def __getitem__(self, index):
            return self.dict.get(index, 0)
        def __setitem__(self, index, value):
            self.dict[index] = value
    
    class Machine:
        def __init__(self, ram=RAM(), pointeur=0):
            self.ram, self.pointeur = ram, pointeur
        def next(self):
            self.pointeur = self.pointeur + 1
        def prev(self):
            self.pointeur = self.pointeur - 1
        def incr(self):
            self.ram[self.pointeur] += 1
        def desincr(self):
            self.ram[self.pointeur] -= 1
        def get_ram(self):
            return self.ram
        def get_pointeur(self):
            return self.pointeur
        def get_case(self):
            return self.ram[self.pointeur]
    
    def sublevel(toplevel, i=0):
        while toplevel[0:i+1].count("[")!=toplevel[0:i+1].count("]"):
            i+=1
        return toplevel[1:i], len(toplevel[1:i])
    
    def parseur(string, bf, i=0):
        while i < len(string):
            if string[i] == "<":
                bf.prev()
            elif string[i] == ">":
                bf.next()
            elif string[i] == "+":
                bf.incr()
            elif string[i] == "-":
                bf.desincr()
            elif string[i] == ".":
                char = raw_input()
                bf.ram[bf.pointeur] = ord(char[0])
            elif string[i] == ",":
                print chr(bf.get_case())
            elif string[i] == "[":
                substring, longueur = sublevel(string[i:])
                i = i + longueur
                while bf.get_case() == 0:
                    parseur(substring, bf)
            i = i + 1
    
    if __name__ == '__main__':
        foo = Machine()
        while True:
            test = raw_input("Brainfuck> ")
            if not test:
                break
            else:
                parseur(test, foo)
    
    • Partager sur Facebook
    • Partager sur Twitter
    yjltg.
      21 août 2010 à 9:49:06

      UP:
      J'ai quelque peu modifié mon code, mais cette fois-ci mon code fait planter IDLE.
      Une idée de ce que j'ai pu oublier ?
      #!/usr/bin/env python
      # -*- encoding: utf-8 -*-
      
      class Machine:
          """
          Simple Turing-machine.
          To get the current cell's value, use machine.case
          You can access directly another cell using machine[cell]
          """
          def __init__(self):
              self.dict = {}
              self.pointeur = 0
          def __getitem__(self, index):
              return self.dict.get(index,0)
          def __setitem__(self, index, value):
              self.dict[index] = value
          def next(self):
              """ Point to next cell"""
              self.pointeur += 1
          def prev(self):
              """ Point to previous cell"""
              self.pointeur -= 1
          def incr(self):
              """ Add one to the cell under the pointer."""
              self[self.pointeur] += 1
          def desincr(self):
              """ Decrease by one the cell under the pointer."""
              self[self.pointeur] -= 1
          def get_case(self):
              return self[self.pointeur]
          def set_case(self, value):
              self[self.pointeur] = value
          case = property(get_case,set_case,doc="the cell under the pointer")
              
      
      def sublevel(toplevel, i=0):
          while toplevel[0:i+1].count("[")!=toplevel[0:i+1].count("]"):
              i+=1
          return toplevel[1:i]
      def del_last(list):
          return list[:-1]
      
      def parseur(string, bf, i=-1):
          stack = []
          while i < len(string)-1:
              i = i + 1
              if string[i] == "<":
                  bf.prev()
              elif string[i] == ">":
                  bf.next()
              elif string[i] == "+":
                  bf.incr()
              elif string[i] == "-":
                  bf.desincr()
              elif string[i] == ",":
                  char = raw_input()[0]
                  bf.case = ord(char)
              elif string[i] == ".":
                  print chr(bf.case)
              elif string[i] == "[":
                  stack.append((i,i+len(sublevel(string[i:]))))
                  if bf.case: # si la case ne vaut pas 0
                      pass # on execute
                  else:
                      i = stack.pop()[1] # on va à la fin de la boucle, on remonte
                      # d'un niveau dans l'arborescence du programme
              elif string[i] == "]":
                  try:
                      i = stack[-1][0]
                  except IndexError:
                      print """Error:
      no corresponding '[' found for the """+i+"""char."""
                      return None
      
                      
      
      if __name__ == '__main__':
          foo = Machine()
          while True:
              test = raw_input("Brainfuck> ")
              if not test:
                  break
              else:
                  parseur(test, foo)
      
      • Partager sur Facebook
      • Partager sur Twitter
      yjltg.
        21 août 2010 à 16:46:15

        Ta gestion des boucles était incorrecte. Essaie plutôt

        elif string[i] == "[":
                    stack.append((i,i+len(sublevel(string[i:]))))
                    i = stack[-1][1] # on va à la fin de la boucle, on remonte
                        # d'un niveau dans l'arborescence du programme
                elif string[i] == "]":
                    try:                
                        if bf.case: # si la case ne vaut pas 0
                            i = stack[-1][0] 
                        else:
                            stack.pop()
                    except IndexError:
                        print """Error:
        no corresponding '[' found for the """+str(i)+"""char."""
                        return None
        
        • Partager sur Facebook
        • Partager sur Twitter
          22 août 2010 à 21:30:58

          Ok, j'ai mis du temps, mais j'ai compris (enfin, je crois).
          En fait, tu vas à la fin de la boucle, et selon si il faut exécuter cette dernière, tu remontes au début de la boucle ? C'est ca ?

          Mais ca serait pas un poil plus rapide si on décidait d'exécuter ou non la boucle avant de sauter à la fin de la dite boucle ?
          • Partager sur Facebook
          • Partager sur Twitter
          yjltg.
            23 août 2010 à 0:05:48

            A vrai dire il faut décider à deux reprises, avant de rentrer dans la boucle et arrivé à la fin de celle-ci. C'était justement le problème de ta version qui bouclait inconditionnellement à la fin de la boucle.

            Aller directement à la fin de la boucle permet de n'avoir qu'un test dans le code (à la fin de la boucle) au lieu de deux.
            • Partager sur Facebook
            • Partager sur Twitter
              23 août 2010 à 14:30:23

              Pas idiot du tout, merci beaucoup :)

              Sujet résolu.
              • Partager sur Facebook
              • Partager sur Twitter
              yjltg.
                23 août 2010 à 20:23:41

                J'en avais fait un aussi à l'époque :)
                import sys
                import getopt
                
                def main(argv):
                	bf = ''
                	
                	try :
                		opts, args = getopt.getopt(argv, "h<:fl", ["help", "file", "line"])
                	except getopt.GetoptError:
                		usage()
                		sys.exit(2)
                	
                	for opt, arg in opts:
                		if opt in ("-h", "--help"):
                			usage()
                			sys.exit()
                		elif opt == '-d' :
                			global _debug
                			_debug = True
                		elif opt in ("-f", "--file"):
                			f = open(args[0], 'r')
                			args = ["".join(f.readlines())]
                		bf = args[0]
                	
                	buff = [0 for x in xrange(30000)]
                	stack = []
                	par = 0
                	pos = 0
                	cro = 0
                	cond = 0
                	char = bf[0]
                	
                	while char :
                		par += 1
                		
                		if char == '+' :
                			buff[pos] += 1
                		elif char == '-' :
                			buff[pos] -= 1
                		elif char == '<' :
                			pos -= 1
                		elif char == '>' :
                			pos += 1
                		elif char == '.' :
                			sys.stdout.write('%c' % buff[pos])
                		elif char == ',' :
                			buff[pos] = ord(sys.stdin.read(1))
                		elif char == '[' :
                			stack.append(par)
                			if buff[pos] == 0 :
                				while bf[par] != ']' :
                					par += 1
                				par += 1
                		elif char == ']' :
                			if buff[pos] != 0 :
                				par = stack.pop()
                				stack.append(par)
                			else :
                				stack.pop()
                		
                		try :
                			char = bf[par]
                		except :
                			char = None	
                
                def usage():
                	print("-f --file \t give a path of a file to interpreter")
                	print("-l --line \t give a line to interpreter")
                	print("-h --help \t show this help")
                		
                if __name__ == "__main__":
                	main(sys.argv[1:])
                


                Si tu veux comparer comme ça :)
                C'est peut-être très mauvais hein, je sais plus quand j'ai fait ça…
                • Partager sur Facebook
                • Partager sur Twitter

                Interpreteur Brainfuck: problème

                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                • Editeur
                • Markdown