今回も前回に引き続き、算術演算命令を実装します。
-
boolean
- スタックトップをポップして、それが 0 以外ならば 1 を、0 ならば 0 をプッシュ
-
((bool)value)
に相当
-
boolnot
- スタックトップをポップして、それが 0 ならば 1 を、それ以外ならば 0 をプッシュ
-
!value
に相当
-
notequal
- スタックトップの 2 数をポップして、それらが等しくなければ 1 を、さもなくば 0 をプッシュ
-
!=
に相当
-
equal
- スタックトップの 2 数をポップして、それらが等しければ 1 を、さもなくば 0 をプッシュ
-
==
に相当
Brainf*ck における条件分岐
boolean
を実装する前に、Brainf*ck における if の実装について触れておきます。
Brainf*ck で条件分岐を行うためにはループを用いるのが唯一の方法です。
以下のコードを実行すると実行開始前の番地が 0 でなければ then
が一度だけ実行されます。
[[-]then]
実行開始前の番地が 0 以外ならば外側のループに入り、その場所は 0 でクリアされます。
外側のループを抜ける際には、]
に至ったときにそこが 0 でなければなりません。
そのために実行開始番地を 0 でクリアして、その場所を利用してループを抜けます。
boolean
命令
if を使うと以下のように実装できます。
[-]< ; 現在の場所をクリアしてスタックトップに移動
[[-]>+<] ; スタックトップが 0 以外ならば、一つ右を 1 にする
> ; 結果が入った位置に移動
[-<+>] ; スタックトップに結果を移動
自動生成するコードは以下です。データポインタの位置は命令実行後に変化しません。
def boolean(self):
assert 0 < self.dp
return '[-]<[[-]>+<]>[-<+>]'
boolnot
命令
boolean
命令の出力を反転させたものが boolnot
命令です。
[-]+< ; 現在の場所をクリアして予め 1 にしておく
[[-]>-<] ; スタックトップが 0 以外ならば、一つ右を 0 にする
> ; 以下同じ
[-<+>] ;
自動生成するコードは以下です。
def boolnot(self):
assert 0 < self.dp
return '[-]+<[[-]>-<]>[-<+>]'
notequal
命令
ここまでくれば notequal
の実装は簡単です。
スタックトップの 2 数の片方から片方を引くと、等しければ 0 に、さもなくばそれ以外になるので、これに boolean
を適用すると notequal
となります。
def notequal(self):
assert 1 < self.dp
code = '<[-<->]' # スタックの 2 番目からスタックトップを引く
self.dp -= 1 # 二項演算なので、データポインタは 1 引く
code += self.boolean()
return code
equal
命令
同様に、引いた結果に boolnot
を適用すると equal
となります。
def equal(self):
assert 1 < self.dp
code += '<[-<->]'
self.dp -= 1
code += self.boolnot()
return code
まとめ
今回は Brainf*ck における if イディオムと、それを使った以下の命令を説明しました。
-
boolean
: スタックトップの bool 化 -
boolnot
: スタックトップの bool 化の後、not -
notequal
: スタックトップの 2 数の不等値比較 -
equal
: スタックトップの 2 数の等値比較
次回は比較命令とそれを使った除算、剰余算命令を解説します。
リポジトリ
記事リンク
- 第 0 回: Brainf*ck による言語処理系
- 第 1 回: 値のロードとストア
- 第 2 回: 加算, 減算, 乗算
- 第 3 回: bool化, 等値比較
- 第 4 回: 非破壊分岐, 比較, 除算, 剰余算
- 第 5 回: while, if, スコープ内変数
- 第 6 回: 配列, 多次元配列
- 第 7 回: コンパイラと言語仕様