Brainfuckの繰り返し処理に少し感動した

Brainfuckというプログラミング言語をPythonで動かしてみて、理解を深めようとしました。
コードはClaudeに書いてもらいました。

PythonでBrainfuckを動かす

import sys
# '>' はポインタをインクリメントする。
# '<' はポインタをデクリメントする。
# '+' ポインタの値をインクリメントする。
# '-' ポインタの値をデクリメントする.
# '.' ポインタの値をutf-8文字で出力する.
# ',' 1バイトの入力を受け付け, その値をポインタのmemに格納する.
# '[' ポインタのバイトが0なら、一致する']'にジャンプする。
# ']' ポインタのバイトが0でない場合、一致する'['にジャンプする。
mem_size = 300
mem = [0 for i in range(mem_size)]
ptr = 0

if __name__ == "__main__":
    args = sys.argv
    path = args[1]
    with open(path) as f:
        code = f.read()
    code_list = list(code)

    head = 0
    while head < len(code_list):
        if code_list[head] == '+':
            mem[ptr] += 1

        elif code_list[head] == '-':
            mem[ptr] -= 1

        elif code_list[head] == '[':
            if mem[ptr] == 0:
                count = 1
                while count != 0:
                    head += 1
                    if head == len(code_list):
                        print("']' is missing")
                        sys.exit(1)
                    if code_list[head] == '[':
                        count += 1
                    elif code_list[head] == ']':
                        count -= 1
        elif code_list[head] == ']':
            if mem[ptr] != 0:
                count = 1
                while count != 0:
                    head -= 1
                    if head < 0:
                        print("'[' is missing")  
                    if code_list[head] == ']':
                        count += 1
                    elif code_list[head] == '[':
                        count -= 1
        elif code_list[head] == '.':
            #chr: char -> code point
            print(chr(mem[ptr]),end = "") #no line break
        elif code_list[head] == ',':
            #ord: code point -> char
            mem[ptr] = ord(sys.stdin.buffer.read(1))
        elif code_list[head] == '>':
            ptr += 1       
            if ptr > mem_size:
                print("overflow!")
                sys.exit(1)
        elif code_list[head] == "<":
            if ptr == 0:
                print("Can't decrement anymore")
            ptr -= 1
        else:
            pass #ignore other symbol

        head += 1   

'[', ']'の意味がいまいち分からん

検証コード

'[', ']'の機能を知らべるために、'['・ ']'の箇所を抽出してコードを実行しました。

mem_size = 30000
mem = [0 for i in range(mem_size)]
ptr = 0

code_list = ">+++++++++[<++++++++>-]<."
count = 0

head = 0 #(tape reading) head
print("ptr, mem[ptr], code_list[head], head, count, chr(mem[ptr])")
while head < len(code_list):
    if code_list[head] == '+':
        mem[ptr] += 1
        print(ptr, mem[ptr], code_list[head], head, count, chr(mem[ptr]))

    elif code_list[head] == '-':
        mem[ptr] -= 1
        print(ptr, mem[ptr], code_list[head], head, count, chr(mem[ptr]))

    elif code_list[head] == '[':
        if mem[ptr] == 0:
            count = 1
            while count != 0:
                head += 1
                if head == len(code_list):
                    print("']' is missing")
                    sys.exit(1)
                if code_list[head] == '[':
                    count += 1
                    print(ptr, mem[ptr], code_list[head], head, count, chr(mem[ptr]), "[ while")
                elif code_list[head] == ']':
                    count -= 1
                    print(ptr, mem[ptr], code_list[head], head, count, chr(mem[ptr]), "[ while")
                else:
                    print(ptr, mem[ptr], code_list[head], head, count, chr(mem[ptr]), "[ while else")
        print(ptr, mem[ptr], code_list[head], head, count, chr(mem[ptr]), "[ end")
    elif code_list[head] == ']':
        print(ptr, mem[ptr], code_list[head], head, count, chr(mem[ptr]))
        if mem[ptr] != 0:
            count = 1
            while count != 0:
                head -= 1
                if head < 0:
                    print("'[' is missing")  
                if code_list[head] == ']':
                    count += 1
                    print(ptr, mem[ptr], code_list[head], head, count, chr(mem[ptr]), "[ while")
                elif code_list[head] == '[':
                    count -= 1
                    print(ptr, mem[ptr], code_list[head], head, count, chr(mem[ptr]), "[ while")
                else:
                    print(ptr, mem[ptr], code_list[head], head, count, chr(mem[ptr]), "[ while else")
        print(ptr, mem[ptr], code_list[head], head, count, chr(mem[ptr]), "[ end")
    elif code_list[head] == '.':
        #chr: char -> code point
        print(chr(mem[ptr]),end = "") #no line break
    elif code_list[head] == ',':
        #ord: code point -> char
        mem[ptr] = ord(sys.stdin.buffer.read(1))
        print(ptr, mem[ptr], code_list[head], head, count, chr(mem[ptr]))
    elif code_list[head] == '>':
        ptr += 1       
        if ptr > mem_size:
            print("overflow!")
            sys.exit(1)
        print(ptr, mem[ptr], code_list[head], head, count, chr(mem[ptr]))
    elif code_list[head] == "<":
        if ptr == 0:
            print("Can't decrement anymore")
        ptr -= 1
        print(ptr, mem[ptr], code_list[head], head, count, chr(mem[ptr]))
    else:
        pass #ignore other symbol

    head += 1

出力結果

ptr, mem[ptr], code_list[head], head, count, chr(mem[ptr])
1 0 > 0 0 
1 1 + 1 0 
1 2 + 2 0 
1 3 + 3 0 
1 4 + 4 0 
1 5 + 5 0 
1 6 + 6 0 
1 7 + 7 0 
1 8 + 8 0
1 9 + 9 0 	
1 9 [ 10 0 	 [ end
0 0 < 11 0 
0 1 + 12 0 
0 2 + 13 0 
0 3 + 14 0 
0 4 + 15 0 
0 5 + 16 0 
0 6 + 17 0 
0 7 + 18 0 
0 8 + 19 0
1 9 > 20 0 	
1 8 - 21 0
1 8 ] 22 0
1 8 - 21 1 [ while else
1 8 > 20 1 [ while else
1 8 + 19 1 [ while else
1 8 + 18 1 [ while else
1 8 + 17 1 [ while else
1 8 + 16 1 [ while else
1 8 + 15 1 [ while else
1 8 + 14 1 [ while else
1 8 + 13 1 [ while else
1 8 + 12 1 [ while else
1 8 < 11 1 [ while else
1 8 [ 10 0 [ while
1 8 [ 10 0 [ end
0 8 < 11 0
0 9 + 12 0 	
0 10 + 13 0 

0 11 + 14 0 
0 12 + 15 0 
0 13 + 16 0 
0 14 + 17 0 
0 15 + 18 0 
0 16 + 19 0 
1 8 > 20 0
1 7 - 21 0 
1 7 ] 22 0 
1 7 - 21 1  [ while else
1 7 > 20 1  [ while else
1 7 + 19 1  [ while else
1 7 + 18 1  [ while else
1 7 + 17 1  [ while else
1 7 + 16 1  [ while else
1 7 + 15 1  [ while else
1 7 + 14 1  [ while else
1 7 + 13 1  [ while else
1 7 + 12 1  [ while else
1 7 < 11 1  [ while else
1 7 [ 10 0  [ while
1 7 [ 10 0  [ end
0 16 < 11 0 
0 17 + 12 0 
0 18 + 13 0 
0 19 + 14 0 
0 20 + 15 0 
0 21 + 16 0 
0 22 + 17 0 
0 23 + 18 0 
0 24 + 19 0 
1 7 > 20 0 
1 6 - 21 0 
1 6 ] 22 0 
1 6 - 21 1  [ while else
1 6 > 20 1  [ while else
1 6 + 19 1  [ while else
1 6 + 18 1  [ while else
1 6 + 17 1  [ while else
1 6 + 16 1  [ while else
1 6 + 15 1  [ while else
1 6 + 14 1  [ while else
1 6 + 13 1  [ while else
1 6 + 12 1  [ while else
1 6 < 11 1  [ while else
1 6 [ 10 0  [ while
1 6 [ 10 0  [ end
0 24 < 11 0 
0 25 + 12 0 
0 26 + 13 0 
0 27 + 14 0 
0 28 + 15 0 
0 29 + 16 0 
0 30 + 17 0 
0 31 + 18 0 
0 32 + 19 0  
1 6 > 20 0 
1 5 - 21 0 
1 5 ] 22 0 
1 5 - 21 1  [ while else
1 5 > 20 1  [ while else
1 5 + 19 1  [ while else
1 5 + 18 1  [ while else
1 5 + 17 1  [ while else
1 5 + 16 1  [ while else
1 5 + 15 1  [ while else
1 5 + 14 1  [ while else
1 5 + 13 1  [ while else
1 5 + 12 1  [ while else
1 5 < 11 1  [ while else
1 5 [ 10 0  [ while
1 5 [ 10 0  [ end
0 32 < 11 0  
0 33 + 12 0 !
0 34 + 13 0 "
0 35 + 14 0 #
0 36 + 15 0 $
0 37 + 16 0 %
0 38 + 17 0 &
0 39 + 18 0 '
0 40 + 19 0 (
1 5 > 20 0 
1 4 - 21 0 
1 4 ] 22 0 
1 4 - 21 1  [ while else
1 4 > 20 1  [ while else
1 4 + 19 1  [ while else
1 4 + 18 1  [ while else
1 4 + 17 1  [ while else
1 4 + 16 1  [ while else
1 4 + 15 1  [ while else
1 4 + 14 1  [ while else
1 4 + 13 1  [ while else
1 4 + 12 1  [ while else
1 4 < 11 1  [ while else
1 4 [ 10 0  [ while
1 4 [ 10 0  [ end
0 40 < 11 0 (
0 41 + 12 0 )
0 42 + 13 0 *
0 43 + 14 0 +
0 44 + 15 0 ,
0 45 + 16 0 -
0 46 + 17 0 .
0 47 + 18 0 /
0 48 + 19 0 0
1 4 > 20 0 
1 3 - 21 0 
1 3 ] 22 0 
1 3 - 21 1  [ while else
1 3 > 20 1  [ while else
1 3 + 19 1  [ while else
1 3 + 18 1  [ while else
1 3 + 17 1  [ while else
1 3 + 16 1  [ while else
1 3 + 15 1  [ while else
1 3 + 14 1  [ while else
1 3 + 13 1  [ while else
1 3 + 12 1  [ while else
1 3 < 11 1  [ while else
1 3 [ 10 0  [ while
1 3 [ 10 0  [ end
0 48 < 11 0 0
0 49 + 12 0 1
0 50 + 13 0 2
0 51 + 14 0 3
0 52 + 15 0 4
0 53 + 16 0 5
0 54 + 17 0 6
0 55 + 18 0 7
0 56 + 19 0 8
1 3 > 20 0 
1 2 - 21 0 
1 2 ] 22 0 
1 2 - 21 1  [ while else
1 2 > 20 1  [ while else
1 2 + 19 1  [ while else
1 2 + 18 1  [ while else
1 2 + 17 1  [ while else
1 2 + 16 1  [ while else
1 2 + 15 1  [ while else
1 2 + 14 1  [ while else
1 2 + 13 1  [ while else
1 2 + 12 1  [ while else
1 2 < 11 1  [ while else
1 2 [ 10 0  [ while
1 2 [ 10 0  [ end
0 56 < 11 0 8
0 57 + 12 0 9
0 58 + 13 0 :
0 59 + 14 0 ;
0 60 + 15 0 <
0 61 + 16 0 =
0 62 + 17 0 >
0 63 + 18 0 ?
0 64 + 19 0 @
1 2 > 20 0 
1 1 - 21 0 
1 1 ] 22 0 
1 1 - 21 1  [ while else
1 1 > 20 1  [ while else
1 1 + 19 1  [ while else
1 1 + 18 1  [ while else
1 1 + 17 1  [ while else
1 1 + 16 1  [ while else
1 1 + 15 1  [ while else
1 1 + 14 1  [ while else
1 1 + 13 1  [ while else
1 1 + 12 1  [ while else
1 1 < 11 1  [ while else
1 1 [ 10 0  [ while
1 1 [ 10 0  [ end
0 64 < 11 0 @
0 65 + 12 0 A
0 66 + 13 0 B
0 67 + 14 0 C
0 68 + 15 0 D
0 69 + 16 0 E
0 70 + 17 0 F
0 71 + 18 0 G
0 72 + 19 0 H
1 1 > 20 0 
1 0 - 21 0 
1 0 ] 22 0 
1 0 ] 22 0  [ end
0 72 < 23 0 H

'[', ']'の意味

どうやら、繰り返し処理を実行してるらしい。

入力:+++++++++[<++++++++>-]<.

  1. ">"で2番目のメモリに移動し、"+++++++++"で9を入力(ここでは繰り返す回数を指定してる)

  2. "["から繰り返し処理を開始する

  3. "<"で1番目ののメモリに移動し、"++++++++"でメモリの値を足していく(ここでは8)

  4. ">"で2番目のメモリに移動し、"-"でメモリの値を減らす(9-1=8, 1回繰り返した)

  5. "]"でコードの読み取り箇所を"["のところまで戻る

  6. "["からもう一回繰り返し処理をする

  7. "<"で1番目のメモリに移動し、"++++++++"でメモリの値を入力(ここでは82=16)

  8. ">"で2番目のメモリに移動し、"-"でメモリの値を減らす(8-1=7, 2回繰り返した)

  9. これらを2番目のメモリの値が0になるまで繰り返す

  10. "<"で1番目のメモリに移動すると、1番目のメモリの値が89=72になる

  11. "."で出力

少し感動

次のメモリに繰り返し回数を指定するのは、よく考えたなぁ。

この記事が気に入ったらサポートをしてみませんか?