descartes-src (ソースパッケージ descartes-src-0.26.0.tar.gz) | 2012-09-09 20:57 |
descartes-win (Windows用バイナリパッケージ descartes-win-0.26.0.zip) | 2012-09-09 20:52 |
会話キャラクター: ツンデレ アプリケーション (会話キャラ:ツンデレ v1.0 for Windows) | 2010-04-29 13:41 |
会話キャラクター: 2人の女の子 ダブルキャラクター (会話キャラクター 2人の女の子 ダブルキャラクター 1.0 for Windows) | 2011-10-02 22:23 |
会話キャラクター: Eliza風英語版 (会話キャラ:Eliza風英語版 v1.0 for Windows) | 2010-05-11 01:06 |
会話キャラクター: 猫耳メイド アプリケーション (会話キャラ:猫耳メイド v1.0 for Windows) | 2010-04-27 21:15 |
会話キャラクター: イライザ風日本語版 (会話キャラ:イライザ風日本語版 v1.0 for Windows) | 2010-04-30 21:53 |
経済指標表示プログラム for Windows (経済指標表示プログラム V1.0) | 2011-08-18 22:04 |
ニュースヘッドライン表示プログラム (ニュースヘッドライン表示プログラム V1.0 for Windows) | 2011-08-16 12:31 |
デカルト言語 example (デカルト言語の例題 example-0.7.0.zip) | 2009-03-01 19:47 |
電力状況表示プログラム for Windows (2011年夏版 全国電力供給状況表示プログラム V1.0) | 2011-08-15 13:25 |
--
← 前のページに戻る
コード領域は、一次元のリスト構造で出来ています。
(命令1 命令2 即値 命令3 文字列 ... )
命令コード, 即値, 文字列, クロージャ名などがリスト内に収納されます。
アドレスは、コードリストの要素の数をリストの先頭から数えた値になります。 このとき、コードリストの要素がたとえ長い文字列であってもアドレスは1しか使わないことに注意してください。
リアルマシンとは異なり、Closure BasicのVMの番地のアドレスは固定バイト長ではなく、要素の数になっています。
まず以下のClosure Basicの例題プログラムを見てください。
dim dt[10] a = 700 print a for i = 0 to 10 print i dt[i] = i next
このプログラムをコンパイルすると次に示すようなコードリストにコンパイルされます。
(PUSHI 18 BRK PUSHI 19 BRK PUSHI closure0 PUSHI 19 PUSHI 700 ROT POP PUSHI closure0 PUSHI 19 PUSH PR NL PUSHI 20 BRK PUSHI closure0 PUSHI 20 DUP2 PUSHI 0 ROT POP PUSHI 10 PUSHI closure0 PUSHI 1 POP DUP2 PUSH PUSHI closure0 PUSHI 1 PUSH CMPLE BRZ 115 PUSHI closure0 PUSHI 1 PUSH PUSHI closure0 PUSHI 20 PUSH PR NL PUSHI closure0 PUSHI 20 PUSH DUP PUSHI 11 CMPLE BRZ 79 DUP PUSHI 0 CMPLT BRZ 82 PUSHI illegal index ERR PUSHI 8 ADD PUSHI closure0 SWAP PUSHI closure0 PUSHI 20 PUSH ROT POP PUSHI closure0 PUSHI 1 POP DUP2 DUP2 PUSH PUSHI 1 ADD ROT POP PUSHI closure0 PUSHI 1 PUSH BR 35 DROP DROP STOP)
最初のPUSHIが0番地、18が1番地、BRKが2番地となります。 最後にSTOP命令が入り、コードリストは終了しています。
命令コードを追加する述語には2種類あります。
::vm <add code #アドレス 命令コード クロージャ名> ::vm <add code #アドレス 命令コード 引数 クロージャ名>
上の述語は、命令コードのみをコード領域に追加します。 下の述語は、命令コードとその引数をコード領域に追加します。
#アドレスは、この述語を呼び出すときに指定するのではなく、命令コードの置かれるアドレスを返すためにあります。
命令コードを追加すると自動的にアドレスが進められ、次の命令コードの追加時には新しいアドレスに追加されることになります。
例えば以下のようなコード生成処理があるとします。
::vm <add code _ PUSHI 18 closure0> ::vm <add code _ BRK closure0> ::vm <add code _ PUSHI 19 closure0> ::vm <add code _ BRK closure0> ::vm <add code _ PUSHI closure0 closure0> ::vm <add code _ PUSHI 19 closure0> ::vm <add code _ PUSHI 700 closure0> ::vm <add code _ ROT closure0>
まるで、アセンブラですね。
#アドレスについては、このコードでは使わないので無名変数_を設定しています。
このコード生成処理により以下のコードが生成されます。
PUSHI 18 BRK PUSHI 19 BRK PUSHI closure0 PUSHI 19 PUSHI 700 ROT
命令コードを変更する述語を次に示します。
::vm <set code アドレス 値 クロージャ名>
クロージャ名のコードのアドレス位置に値を使って強制的に書き直します。
通常の命令コードの出力には、前項で示した::vm <add ~>の命令が便利なのですが、 この::vm <set ~>命令は、分岐やループするコードを出力する場合に飛び先アドレスを 設定するのに主として使います。
例えば以下のコードを見てください。
::vm <add code _ BRZ #cl> ::vm <add code #braddr1 -1 #cl> ~ ::vm <add code #braddr2 PUSHI 1 #cl> ::vm <set code #braddr1 #bradd2 #cl> ~
最初のBRZ命令は次のコードに書いてあるアドレスにブランチします。
しかし、このコードを出力している時点では、まだ飛び先のアドレスがわからないので、取り敢えず-1を入れておきます。 アドレス-1は存在しないアドレスなので、もし間違って本当のアドレスと置き換え忘れても、実行時に異常終了するのでわかります。
前の項で説明したとおり、add述語では、第2引数には追加されたコードのアドレスが設定されて返されます。
変数#braddr1には、この-1が入っているアドレスが設定されるので、覚えておきます。
そして、飛び先アドレスが決定されます。上の例では#braddr2アドレスがそのアドレスです。
そのとき、先ほどの#braddr1の-1の入っているコード領域を、#braddr2のアドレスに置き換えます。 これでブランチ先のアドレスが正しくコードに設定されました。
このように、すぐには確定できないアドレスの解決にset述語は使われます。
命令コードと同様にクロージャ内のデータ領域の初期化を行うことも出来ます。
::vm <add data #アドレス データ初期値 クロージャ名> ::vm <set data アドレス データ初期値 クロージャ名>
addもsetも命令コード領域への追加と更新と同様に使えます。第1引数が"data"となっていることに着目してください。
実はClosure Basicでは、データの初期化はすべて命令コードで値を設定してしまいます。 データを確保して、値をそのデータ領域のメモリへの値の設定をプログラム上でストアします。 そのため、ここで説明している初期化は使っていません。
しかし、将来の機能追加や別仕様言語への適用などを考えて、データ初期化の方法をVM機能に追加してあります。
[ページ情報]
更新日時: 2011-06-22 22:14:39, 更新者: hniwa
[ライセンス]
クリエイティブ・コモンズ 2.1 表示
[権限]
表示:無制限, 編集:ログインユーザ, 削除/設定:ログインユーザ