このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

JavaScriptで仮想機械の勉強をしましょう (その4 サブルーチン呼び出し)

RAC1プログラム サンプルページを少しだけ更新しました。

サンプルを2つ追加しました。

  1. サブルーチンを使って x22 + y22 を計算する
  2. fact(j) + fact(k) を計算する

このサンプル・タイトルからもわかるように、サブルーチン呼び出し機能を追加しました。


多くのハードウェアでは、スタックが1本だけのことが多いので、スタック領域全体をスタックフレームという区画に分けて、スタックフレーム内にサブルーチン(関数、手続き)の引数、ローカル変数、戻り番地などを詰め込みます。

標準的スタックフレームを使う場合のサブルーチン呼び出しは、スタックポインタ、フレームポインタ、プログラムカウンタなどのレジスタを操作します。これはけっこうややこしい。2006年に半分くらい説明した記事があります(残り半分の続きはないです(苦笑))。

ほかにもスタック関係の記事がありますね。

今回の、JavaScriptで書いたオモチャの仮想機械RAC1では、ややこしい方法は避けて、スタックを2本使ってみました。VM(仮想機械)オブジェクトが持っている変数は次のものです。このなかで制御スタックctrlをサブルーチン呼び出しに使います。

    this.code = code;     // 実行するコード
    this.pc = 0;          // プログラムカウンタ
    this.stack = stack;   // 計算用スタック
    this.ctrl = [];       // 制御スタック

CALL命令とRET命令の実行は次のような処理となります。

    case CALL:
        param = code[this.pc++]; // 呼び出す先のラベル
        this.ctrl.push(this.pc); // 戻り番地を制御スタックに積む
        this.scopes.openBlock(); // 局所変数領域を確保する
        this.jump(param);        // サブルーチン入り口に飛ぶ
        break;
    case RET:
        this.scopes.closeBlock(); // 局所変数領域を開放する
        this.pc = this.ctrl.pop();// 制御スタックトップの戻り番地に飛ぶ
        break;

変数は計算スタックとは別に管理されているし、戻り番地も専用の制御スタックを使うので、CALL/RETの手順は単純です。実際のハードウェアを忠実にエミュレータしたいなら話は別ですが、好きに作れる仮想機械ですから、スタックをたくさん使ってもいいでしょ。