- 追加された行はこのように表示されます。
- 削除された行は
このように表示されます。
Forthには、スタックだけでなく、変数も利用できる。
文法はこうなる:
variable hoge
[[ANS Forthの規格|ANSI X3.215-1994 Programming Languages Forth]]には、"6.1.2410 VARIABLE"にその説明がある。
それによると、構文解析時には変数となる番地を割り当て、実行時にはその番地をスタックにPUSHする。
、、、すみません。今日は2010年12月28日。一年以上更新をサボっていました。
えーと、何をやっていたのか、すっかり忘れていますので、おさらい。
構文解析時:
*"variable hoge"が現れたら、hogeを変数名テーブルに登録する
*hogeと実際に保存される番地との関連付けが必要
*hogeがプログラム中に単独で現れたら、hogeに関連付けられた番地をスタックにPUSHするコードに置き換える
実行時:
*hogeは番地をPUSHするコードになっているので、ただ実行するだけ
、、、おさらい終わり、、、
作ってみよう。
まず、どうすればいいだろう?
構文解析時にvariableを見つけたら、次にくる文字列は変数名である。
そこで、この時点で文字列と割り当てるメモリ領域の先頭番地を、変数名-アドレス変換テーブルに保存する。
これのための構造体を作ろうと思ったが、以前作ったワード名-番地変換テーブルの構造と同じだった。
/**
* ワード名-処理番地の組
*/
typedef struct word_proc_table {
char word_pointer; /**< ワード名が登録されたヒープへの番地 */
char proc_pointer; /**< 登録された処理番地 */
} WORD_PROC_TABLE;
そこで、名前を変更し、両方に使えるようにする。
/**
* 名前-実体番地の組
*/
typedef struct name_instance_pair {
char name_pointer; /**< 名前が登録されている位置 */
char instance_pointer; /**< 実体が登録されている位置 */
} NAME_INSTANCE_PAIR;
そして、変数領域を宣言する。
NAME_INSTANCE_PAIR var_table[100]; /**< 変数管理テーブル */
unsigned char var_table_head; /**< 変数管理テーブルの未使用位置の先頭 */
unsigned char var[100]; /**< 変数実体の格納領域 */
int var_pos; /**< 変数実体領域の未使用領域の先頭を指す */
char varname_heap[100]; /**< 変数名登録領域 */
unsigned char varname_heap_index; /**< 変数名登録領域の未使用領域の先頭を指す */
構文解析時の処理。まず、variable。parse()に追加する。
} else if (strcmp(token, "variable") == 0) {
/* 続くトークンを変数とする */
token = get_token(NULL);
assoc_var_name(token);
assoc_var_name()は、引数として渡されたトークン文字列と自動的に割り当てられた実体番地を、構造体配列var_table[]に登録する。
/**
* 変数名と実体番地とを関連付ける
*/
void assoc_var_name(unsigned char *name)
{
/* 変数名をヒープ領域に登録する */
var_table[var_table_head].name_pointer = reg_var_name(name);
/* 変数の割り当て番地を登録する */
var_table[var_table_head].instance_pointer = var_pos;
var_pos += 2;
/* 使っていない登録テーブルを先頭にする */
var_table_head++;
}
ワード内容に変数名が現れたら、変数の値が割り当てられた番地を埋め込む。
CODE_VARADRは、動作はCODE_PUSHと同じである。
同じくparse()に追加する。
get_var_address()は、トークンが登録されていなければ、-1を返す。
} else if ((adrs = get_var_address(token)) >= 0) {
/* 変数の番地をスタックにPUSHする */
prog[parse_idx] = CODE_VARADR;
prog[parse_idx + 1] = adrs;
parse_idx += 2;
実行時の処理。
/**
* 変数の番地をスタックに積む
*/
void call_varadr(void)
{
push(prog[prog_cnt]);
prog_cnt++;
}
テストプログラム。プログラムが正しければ、var_table[ ].instance_pointerの値を表示するはず。
テストプログラム。コードが正しければ、var_table[ ].instance_pointerの値(変数の番地ではなく、var[]の添字)を表示するはず。
variable x x . cr
variable y y . cr
実行してみる。
$ ./moiforth.exe testfile/test9
0
2
成功した。
[ソースコード|http://www.moi2.sakura.ne.jp/fswiki/wiki.cgi?page=Forth%A4%F2%BA%EE%A4%C3%A4%C6%A4%DF%A4%EB+%2F+%CA%D1%BF%F4%A4%F2%BC%C2%C1%F5%A4%B9%A4%EB&file=moiforth%2D0%2E10%2Ezip&action=ATTACH]
次回、変数の参照と代入を行う。
(2011.01.03)
[[戻る|Forthを作ってみる]] [[前へ|Forthを作ってみる / 文字列を表示する]] [[次へ|Forthを作ってみる / 変数を実装する2]]
{{adsence}}