前回、Forthを作ってみる / 変数を実装するによって、変数の番地をスタックにPUSHできるようになった。次は、変数の実体に対してアクセスできるようにする。
変数へのアクセスには、"@"と"!"を用いる。
@ 変数の値の参照 (addr -- x) ! 変数への値の代入 (x addr -- )
変数yの値を参照するには、
y @
変数yへ値5を代入するには、
5 y !
のように書く。
まず@の(実行時の)実装について考える。プログラム実行時、@の中間コード(CODE_AT)が現れたら、
- すでにスタックに積まれているはずの、変数の番地addrを取り出す
- その値は、var[ ]のインデックスであるので、var[addr]の値をスタックに積む
次に!の(実行時の)実装について考える。プログラム実行時、!の中間コード(CODE_EXCL)が現れたら、
- すでにスタックに積まれているはずの、変数の番地addrを取り出す
- すでにスタックに積まれているはずの、代入値valを取り出す
- addrは、var[ ]のインデックスであるので、var[addr]にvalを代入する
プログラムを書いてみよう。
コードに"@"と"!"が現れたときの処理をparse()に追加する。
} else if (strcmp(token, "@") == 0) { prog[parse_idx] = CODE_AT; parse_idx++; } else if (strcmp(token, "!") == 0) { prog[parse_idx] = CODE_EXCL; parse_idx++;
参照と代入の処理関数。
/** * 変数を参照し、スタックに積む */ void call_var_load(void) { /* 変数の番地を取り出す */ long addr = pop(); /* 変数の値をスタックに積む */ push(var[addr]); } /** * 変数に値を代入する */ void call_var_store(void) { /* 変数の番地を取り出す */ long addr = pop(); /* 代入値を取り出す */ long val = pop(); /* 変数に値を代入する */ var[addr] = val; }
関数ポインタ配列に上記関数を追加する。
void (*jump_table[])(void) = { /**< ワードのジャンプ先テーブル */ NULL, call_push, plus, print, word_if, word_else, word_then, call_do, call_loop, call_i, call_cr, call_word, proc_ret, call_dotquote, call_varadr, call_var_load, call_var_store };
テストコードで動作を確認する。
variable x 5 x ! x @ . cr variable y 10 y ! y @ . cr
実行する。
$ ./moiforth.exe testfile/test10 5 10
できた。
(2011.01.10)
- Amazonリンク
- Thinking Forth
moiforth-0.11.zip