Seite 1 von 2

Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 11:20
von fail
Aus irgendeinem Grund passiert nichts, es lauft die ganze Zeit und gibt nichts aus. Was hab ich falsch gemacht?

Code: Alles auswählen

def brainfucker(code,index=0,zellen=[0]*30000):
    code=code
    zellen=zellen
    index=index
    for t in code:
        if t==">":
            index +=1
            
        elif t=="<":
            index -=1
            
        elif t=="+":
            zellen[index] +=1

        elif t=="-":
            zellen[index] -=1

        elif t==".":
            print(zellen[index], end="")

        elif t==",":
            zellen[index] = ord(input())

        elif t=="[":
            while zellen[index] != 0:
                brainfucker(code[code.index(t):code.find("]", code.index(t))],index,zellen)
    

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 11:27
von /me
fail hat geschrieben:Aus irgendeinem Grund passiert nichts, es lauft die ganze Zeit und gibt nichts aus. Was hab ich falsch gemacht?
Du rufst die Funktion nicht auf. Was soll eigentlich dieses code=code und zellen=zellen?

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 11:35
von fail
liegt nicht an dem

Code: Alles auswählen

def brainfucker(code,index=0,zellen=[0]*30000):
    for t in code:
        if t==">":
            index +=1
            
        elif t=="<":
            index -=1
            
        elif t=="+":
            zellen[index] +=1

        elif t=="-":
            zellen[index] -=1

        elif t==".":
            print(zellen[index], end="")

        elif t==",":
            zellen[index] = ord(input())

        elif t=="[":
            while zellen[index] != 0:
                brainfucker(code[code.index(t):code.find("]", code.index(t))],index,zellen)
                
                
brainfucker("""++++++++++
 [
  >+++++++>++++++++++>+++>+<<<<-
 ]                       Schleife zur Vorbereitung der Textausgabe
 >++.                    Ausgabe von 'H'
 >+.                     Ausgabe von 'e'
 +++++++.                'l'
 .                       'l'
 +++.                    'o'
 >++.                    Leerzeichen
 <<+++++++++++++++.      'W'
 >.                      'o'
 +++.                    'r'
 ------.                 'l'
 --------.               'd'
 >+.                     '!'
 >.                      Zeilenvorschub
 +++.                    Wagenrücklauf""")
    

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 11:48
von BlackJack
@fail: Hast Du selbst denn schon mal versucht mit ``print``-Anweisungen heraus zu finden bis wohin die Ausführung kommt, oder wo sie hängen bleibt? Wenn `code` einfach nur '.' ist, dann wird auch nichts ausgegeben? Hast Du mal systematisch verschiedene BF-Programme geschrieben um die einzelnen Befehle zu testen?

Deine Behandlung von '[' ist falsch. Zum einen findet der ``code.index(t)``-Aufruf immer nur die erste '[' im `code`, also jedes BF-Programm mit mehr als einem '[' wird nicht funktionieren.

Wenn dort die richtige Klammer gefunden *würde*, dann hast Du auch noch das Problem, dass der „Rücksprung” bei Dir den Datenzeiger zurücksetzt, was nicht sein darf. Ich würde an Deiner Stelle die Rekursion weg lassen und einen expliziten Programmzeiger einführen und mit einer Liste einen Aufrufstapel implementieren.

Veränderbare Default-Werte sind gefährlich. Der Wert für `zellen` wird nur *einmal* ausgewertet wenn das ``def`` für die Funktion ausgeführt wird und *nicht* jedes mal wenn man die Funktion aufruft! Das heisst wenn man die Funktion mehrfach nur mit `code` aufruft, dann wird nicht etwas jedes mal mit einem mit Nullen gefüllten Speicher gearbeitet, sondern die `zellen` enthalten die Werte vom letzten Durchlauf.

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 12:01
von fail
Eine Frage:

Code: Alles auswählen

for t in "string":
und t ist beim 3 Durchlauf und ist bei "r"
kann ich t wieder auf z.B. "s" setzen oder muss ich das mit einer while schleife machen?

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 12:27
von Hyperion
fail hat geschrieben: kann ich t wieder auf z.B. "s" setzen oder muss ich das mit einer while schleife machen?
Nein Du kannst das nicht wieder zurücksetzen. Aber was meinst Du mit while-Schleife?

Generell gefällt mir diese ``if...elif``-Kaskade nicht. So etwas kann man idR. vermeiden, indem man ein Dispatching definiert, welches vom Wert in der Bedingung auf ein Callable mappt. In Deinem Falle also z.B. so:

Code: Alles auswählen

command_mapping = {
    "<": move_right,
    ">": move_left,
    "+": inc,
    "-": dec,
    # usw...
}

# und dann als Aufruf:
command_mapping[t](index, zellen)
Die Werte im Dictionary sind eben zuvor definierte Callables (also Funktionsobjekte, Lambdas usw).

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 12:33
von fail
mach ich dann beim refactoring jetzt hab ich schon so angefangen

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 14:04
von fail
habe immernoch ein problem mit den schleifen

Code: Alles auswählen

def brainfucker(code):
    cellindex=0
    cells=[0]*30000
    codeindex=1
    stack_codeindex=[]
    stack_cellindex=[]
    while codeindex <= len(code):
        if code[codeindex]==">":
            cellindex +=1
            codeindex +=1
            print("vorne")
            
        elif code[codeindex]=="<":
            cellindex -=1
            codeindex +=1
            print("hinten")
            
        elif code[codeindex]=="+":
            cells[cellindex] +=1
            codeindex +=1
            print("inkrementieren")

        elif code[codeindex]=="-":
            cells[cellindex] -=1
            codeindex +=1
            print("dekrementieren")

        elif code[codeindex]==".":
            print(cells[cellindex], end="")
            codeindex +=1
            print("output")

        elif code[codeindex]==",":
            cells[cellindex] = ord(input())
            codeindex +=1
            print("input")

        elif code[codeindex]=="[":
            stack_codeindex.append(codeindex)
            stack_cellindex.append(cellindex)
            codeinex +=1
            print("schleifenanfang")

        elif code[codeindex]=="]":
            last=stack_cellindex[-1]
            if last!= 0:
                codeindex=stack_codeindex[-1]

            else:
                stack_cellindex.pop
                stack_codeindex.pop
                codeindex +=1
            print("schleifenende")
            
            
                
                

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 14:29
von BlackJack
@fail: Jetzt baust Du mit dem `stack_cellindex` den gleichen Fehler nach, den Du vorher durch den rekursiven Aufruf hattest. Weder '[' noch ']' verändern den `cellindex`. Du brauchst dafür keinen Stack!

Und beim `stack_codeindex` nimmst Du die Elemente nicht wieder herunter. Einfach die Methode zu referenzieren bringt nichts, Du musst sie auch *aufrufen*. Und dann könntest Du auch gleich deren Rückgabewert verwenden und damit die Zeile sparen wo Du über den Index -1 auf das letzte Element zugreifst. Das wird von `pop()` ja zurückgegeben.

Da `codeindex` in jedem bis einem Zweig um eins erhöht wird, solltest Du das aus allen Zweigen herausnehmen und hinter die Befehlsauswertung setzen. Der eine Zweig in dem der `codeindex` auf einen Wert gesetzt wird, muss ihn dann halt auf diesen Wert minus eins setzen. Dann funktioniert Dein Interpreter auch wieder mit `code` der andere Zeichen als ausschliesslich BF-Befehle enthält.

Diese ständige ``code[codeindex]``-Wiederholung sollte man vermeiden und den Wert vor der Schleife einmal ermitteln.

Warum eine Schleife die genau am Anfang von `code` bei ']' anders behandelt wird als alle anderen Schleifen verstehe ich nicht. Auch nicht warum die dann *so* behandelt wird.

Anstelle der ``print()``-Anweisungen könntest Du das `logging`-Modul verwenden und `debug()`-Meldungen ausgeben. Die Ausgaben kann man dann einfach unterdrücken wenn man mit der Fehlersuche fertig ist und bei Bedarf auch wieder einschalten.

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 15:53
von fail
Jetz hab ich immer wieder list index out of range

Code: Alles auswählen

def bf(code):
    cellindex=0
    cells=[0]*30000
    codeindex=0
    stack_codeindex=[]
    while codeindex <= len(code):
        index=code[codeindex]
        if index==">":
            cellindex +=1
            #print("vorne")
        elif index=="<":
            cellindex -=1
            #print("hinten")
        elif index=="+":
            cells[cellindex] +=1
            #print("inkrementieren")
        elif index=="-":
            cells[cellindex] -=1
            #print("dekrementieren")
        elif index==".":
            print(chr(cells[cellindex]), end="")
            #print("output")

        elif index==",":
            cells[cellindex] = ord(input())
            #print("input")

        elif index=="[":
            stack_codeindex.append(codeindex)
            #print("schleifenanfang")

        elif index=="]":
            if cells[cellindex]!= 0:
                codeindex=stack_codeindex[-1]
                codeindex -=1

            else:
                stack_codeindex.pop
            #print("schleifenende")
            
        codeindex +=1    
                
                

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 16:31
von Sirius3
Den IndexError, dessen Stacktrace Du gerne auch posten darfst, kannst Du doch ganz einfach selbst lösen, indem Du schaust, welcher Index da überläuft und warum.

Backjacks pop-Anmerkung scheinst Du ignoriert zu haben. Brainf*** evaluiert die Bedingung im übrigen am Schleifenanfang und nicht erst am Ende.

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 17:11
von fail
stacktrace

Code: Alles auswählen

bf("""++++++++++
 [
  >+++++++>++++++++++>+++>+<<<<-
 ]                       Schleife zur Vorbereitung der Textausgabe
 >++.                    Ausgabe von 'H'
 >+.                     Ausgabe von 'e'
 +++++++.                'l'
 .                       'l'
 +++.                    'o'
 >++.                    Leerzeichen
 <<+++++++++++++++.      'W'
 >.                      'o'
 +++.                    'r'
 ------.                 'l'
 --------.               'd'
 >+.                     '!'
 >.                      Zeilenvorschub
 +++.                    Wagenrücklauf""")
Hello World!

Traceback (most recent call last):
  File "<pyshell#5>", line 18, in <module>
    +++.                    Wagenrücklauf""")
  File "C:\Python33\z_MyScripts\brainfucker.py", line 7, in bf
    index=code[codeindex]
IndexError: string index out of range

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 17:13
von fail
könnt ihr mir helfen mit dem Schleifenbedingung am anfang auswerten ich weiss nicht wie?

Code: Alles auswählen

def bf(code):
    cellindex=0
    cells=[0]*30000
    codeindex=0
    stack_codeindex=[]
    while codeindex <= len(code):
        index=code[codeindex]
        if index==">":
            cellindex +=1
            #print("vorne")
        elif index=="<":
            cellindex -=1
            #print("hinten")
        elif index=="+":
            cells[cellindex] +=1
            #print("inkrementieren")
        elif index=="-":
            cells[cellindex] -=1
            #print("dekrementieren")
        elif index==".":
            print(chr(cells[cellindex]), end="")
            #print("output")

        elif index==",":
            cells[cellindex] = ord(input())
            #print("input")

        elif index=="[":
            stack_codeindex.append(codeindex)
            #print("schleifenanfang")

        elif index=="]":
            if cells[cellindex]!= 0:
                codeindex=stack_codeindex[-1]
                codeindex -=1

            else:
                stack_codeindex.pop()
            #print("schleifenende")
            
        codeindex +=1    
                
                

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 17:56
von darktrym
Ich tippe mal auf folgendes Problem:
>>> s = "hello"
>>> len(s)
5
>>> s[5]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
Nebenbei kann man sich das sparen indem man ein nicht vorkommenes Zeichen am Ende des Code anfügt und eine weiteren Opcode-Auswertungszweig mit Abbruch.

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 18:07
von BlackJack
@fail: Der `IndexError` und die Bemerkung von Sirius3 zum Schleifenanfang haben nichts miteinander zu tun. Zum `IndexError` hat darktrym ja schon etwas gesagt.

Was den Schleifenanfang angeht: Formuliere doch mal präzise in Worten was der BF-Interpreter machen muss, wenn er auf ein '[' trifft. *Das* musst du dann in Code umsetzen wenn ein '[' vorkommt. Statt einen Stapel zu verwenden, könnte man ganz am Anfang auch eine Datenstruktur erstellen wo für jede Klammer der Index der jeweilig zugehörigen anderen Klammer gespeichert wird. Dann braucht man während des Programmablaufs nicht ständig die passende Endklammer suchen, sondern kann direkt darauf zugreifen. Im Zuge dessen könnte man auch gleich die ganzen Zeichen ausfiltern, die keine BF-Befehle sind, damit man sich beim BF-Programmablauf das überlesen dieser Zeichen sparen kann.

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 18:40
von fail
Ein fehler weg ein neuer dazu die ASCII ausgaben des Hello Worlds programm stimmen nicht.

Code: Alles auswählen

def bf(code):
    code=[s for s in code if s in ("<",">","+","-",".",",")]
    cellindex=0
    cells=[0]*30000
    codeindex=0
    stack=[]
    while codeindex < len(code):
        index=code[codeindex]
        if index==">":
            cellindex +=1
           
        elif index=="<":
            cellindex -=1
            
        elif index=="+":
            cells[cellindex] +=1
           
        elif index=="-":
            cells[cellindex] -=1
            
        elif index==".":
            print(chr(cells[cellindex]), end="")
         

        elif index==",":
            cells[cellindex] = ord(input())
        

        elif index=="[":
            if cells[cellindex]== 0:
                stack.append(codeindex)
                codeindex=code.index("]",codeindex)
                
        

        elif index=="]":
            codeindex=stack.pop()
            codeindex -=1
            
               
        codeindex +=1    
                
                

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 18:51
von BlackJack
@fail: Die Behandlung von '[' ist falsch. Eventuell hast Du den Zweck von dem Stack nicht verstanden und wann der wofür benutzt werden muss. Mach Dir das mal an einem ganz einfachen Beispiel klar. Spiel das in Gedanken durch, sei Python-Interpreter und scheibe Dir für jeden Programmschritt die aktuellen Werte auf ein Blatt Papier.

Ausserdem ist die Suche der passenden schliessenden Klammer falsch. Zum einen der selbe Fehler den ich schon bei der rekursiven Variante ganz am Anfang mal angemerkt hatt: Es wird immer nur nach der *ersten* Klammer im gesamten `code` gesucht. Aber selbst wenn man das anpasst zu „suche die erste schliessende Klammer ab der aktuellen öffnenden Klammer”, ist das immer noch zu simpel gedacht, denn Du musst nicht die *erste*, sondern die *passende* Klammer suchen. Beide Fehler würden bei dem „Hallo Welt”-Programm noch nicht auffallen, aber auch nur weil es nicht mehrere und auch keine verschachtelten Klammern in dem Programm gibt.

Edit: Die Behandlung von ',' entspricht übrigens auch nicht der BF-Definition. Da soll nicht ein Zeichen plus Eingabetaste gelesen werden, sondern wirklich nur ein Bytewert von der Standardeingabe.

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 18:57
von fail
Okay jetzt hab ich Probleme erstens wie finde ich die passende Klammer?
und zweitens wie kann ich nur ein zeichen lesen lassen?

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 18:58
von Sirius3
Hat zwar nichts mit fails Problemen zu tun, aber hier mal ein bf2py-Converter:

Code: Alles auswählen

cmds={
    '>':'i+=1',
    '<':'i-=1',
    '+':'c[i]+=1',
    '-':'c[i]-=1',
    '.':'sys.stdout.write(chr(c[i]))',
    ',':'c[i]=ord(sys.stdin.read(1))',
    '[':'while c[i]:',
}
brackets= {'[':1, ']':-1}
def bf(code):
    pcode=["c=[0]*100","i=0"]
    ind=0
    for c in code:
        if c in cmds:
            pcode.append(' '*ind+cmds[c])
        ind+=brackets.get(c,0)
    exec '\n'.join(pcode)

Re: Brainfuck Interpreter

Verfasst: Sonntag 24. Februar 2013, 19:05
von fail
Die erste öffnende Klammer schliesst sich mit der letzten schliessender Klammer.
Die zweite öffnende Klammer schliesst sich mit der zweitletzten schliessender Klammer.

etc.

Oder?