スタックマシン
基本操作は、pushとpopの2つ
LIFO
アクセス可能な場所は一番上のみ
シンプル、プログラムサイズが小さい傾向がある
順序依存が大きいので、命令の並び替えによる最適化には向いていない
スタックマシンとそれに対応するコンパイラは実装が簡単
必要な部品が少ない
命令もスタックを利用する命令なので実装が簡単
しかし、命令の数は多くなる
pushしたりpopしたりして演算したりするから
このことはパフォーマンスにも影響がある
push
一番上にデータを積む
pop
一番上のデータを取り出す
スタック算術
加算の例
txt// 例 d = (2-x)*(y+5)
push 2
push x
sub
push y
push 5
add
mult
pop d
add
スタックマシンのスタックトップから2つpopし、加算し、結果をスタックへpushする
ブール式の評価の例
txt// if (x<7) or (y=8) then ...
// xとyのメモリに入っている値が、x=12, y=8の時を考える
push x
push 7
lt // ここで12<7を評価してスタックに`false`をpush
push y
push 8
eq // ここで8==8を評価してスタックに`true`をpush
or // false or trueを計算して`true`をpush
最終的にスタックには true
がある状態になる
Pythonでdisライブラリを使って
プロセスVMが実行する命令列を確認できる
py>>> import dis
>>> dis.dis(lambda x,y,z: (x+y)*z)
1 0 LOAD_FAST 0 (x) # push x
2 LOAD_FAST 1 (y) # push y
4 BINARY_ADD # add
6 LOAD_FAST 2 (z) # push z
8 BINARY_MULTIPLY # mult
10 RETURN_VALUE
サブルーチン呼び出しをスタックマシンを使って表現する
サブルーチンとは、関数のようなもので、呼び出されたときに、メインのルーチンから別れたサブルーチンへ行き、処理が終わるとそこへ戻ってくるようなもの
サブルーチン呼び出し時には、以下のような処理が起こる
メインのルーチン(サブルーチンの呼び出し側)の状態を保存し、
サブルーチンのローカル変数のためのメモリを確保し
サブルーチンへの実行を移す(junmp)
処理が終われば、メインのルーチンへ戻るために値を返し(return)
先程確保したメモリ空間を再利用できる状態にし、
メインの状態を復帰させる
引数をpushしたあとに、関数命令を実行、そしてその結果をスタックにpush
ir// x^3
push x
push 3
call power
サブルーチン呼び出し時に、呼び出し元の状態をスタックにpushしたあとで、サブルーチンに実行に切り替える
逆ポーランド記法とか
参考