データ・スタックに加えて、 Forth には 2 番目のスタックであるリターン・スタックもあります。 ほとんどの Forth システムは、プロシージャ呼び出しの戻りアドレスをそこに保存します(したがって、 リターン・スタックという名前が付けられています)。 プログラマもリターン・スタックを利用することができます。
: foo ( n1 n2 -- ) .s >r .s r@ . >r .s r@ . r> . r@ . r> . ; 1 2 foo
>r
はデータ・スタックから1つの要素を取得し、 それをリターン・スタックにプッシュします。 逆に、 r>
は1つの要素をリターンからデータ・スタックに移動します。 r@
は、リターン・スタック頂上のコピーをデータ・スタックにプッシュします。
Forth プログラマーは通常、 データ・スタックのみを使用すると複雑すぎて、 かつ、 ファクタリングやローカル変数が選択肢に無い場合、 データを一時的に保存するためにリターン・スタックを使用します。
: 2swap ( x1 x2 x3 x4 -- x3 x4 x1 x2 ) rot >r rot r> ;
定義のリターン・アドレスとカウント付きループのループ制御パラメーターは通常、 リターン・スタック上に存在するため、 コロン定義またはカウント付きループでリターン スタックにプッシュしたすべての項目を、定義の終了やループの終了の前にリターン・スタックから取得する必要があります。 ある定義の外側やループの外側でリターン・スタックにプッシュしたアイテムに、 ループの定義内からアクセスすることはできません。
リターン・スタック項目の数を間違えると、 通常はクラッシュします:
: crash ( n -- ) >r ; 5 crash
ローカル変数の使用とリターン・スタックの使用を混在させることはできません(標準Forthの場合。 Gforth では問題ありません)。 ただし、 これらは同一の問題の解決なので、 問題にはなりません。
研究課題(assignment): リターン・スタックを使用して、 ここまでにあなたが書いた定義をより良い方法で書き直すことができるでしょうか?
こちらも参照ください: Return stack