トップ 一覧 Farm 検索 ヘルプ RSS ログイン

Forthを作ってみる / 変数を実装するの変更点

  • 追加された行はこのように表示されます。
  • 削除された行はこのように表示されます。
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}}