前回に引き続きBrainf*ckのトランスレータを見ていきます。
Brainf*ckでは変数の指すメモリの中身が0以外の間だけ回るループがあります。
# while (*(char *)esi) { ... } start_loop: cmpb $0, (%esi) jz end_loop # ... jmp start_loop end_loop:
cmp命令で0と比較して、一致した場合(jz)はend_loopに飛んで抜けます。jmpは無条件でstart_loopに飛びます。
ループが複数ある場合、ラベル(start_loop, end_loop)に別の名前を付ける必要があります。連番を振れば簡単そうですが、ループがネストすると厄介です。
相対ラベル
ラベルを局所化するテクニックとして相対ラベルがあります。数字のみのラベルが相対ラベルとして扱われます。参照元から見て前(f)か後(b)かをラベルの接尾辞に添えて指定します。相対ラベルは重複しても構いません。
※前・後の方向については次のセクションで取り上げます。
0: cmpb $0, (%esi) jz 0f # ↓方向に0:を探す # ... jmp 0b # ↑方向に0:を探す 0:
前・後
前か後かという表現はパーサの進行方向を基準としています。パーサはプログラムを先頭から見ていくため、画面での下が前に相当します。
後 ↓ ↓ ↓ 前
直感的に判断すると画面での上が前のように思えてしまうため、慣れが必要な表現です。
ネスト
ループがネストする場合、ネストレベルを相対ラベルの値に割り当てます。うまくペアができていることを確認してください。
0: cmpb $0, (%esi) jz 0f 1: cmpb $0, (%esi) jz 1f # ... jmp 1b 1: jmp 0b 0:
上記では読みやすいようにインデントしています。Pythonとは異なり、インデントに文法的な意味はありません。