Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
@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.
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:
@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.
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.
>>> 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.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008] Bitbucket, Github
@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.
@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.
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)
Die erste öffnende Klammer schliesst sich mit der letzten schliessender Klammer.
Die zweite öffnende Klammer schliesst sich mit der zweitletzten schliessender Klammer.