Forth のスタックは、数値情報の一時的保持用の後入れ先出し型 (LIFO) バッファーです。これを積み重ねられた本と考えてみてください。その場合、最後に置いた、つまり本の積み重ねの一番上に乗せた本から先に取ることになります。Forth を使用するには、スタックを理解することが不可欠です。
スタックに数値を入れる (一番上に乗せる) には、単にその値を入力します。
ok 44 (値 44 がスタックの一番上に乗る) ok 7 (値 7 がスタックの一番上に乗る) ok |
スタックの内容は通常は表示されません。しかし、希望する結果を得るためには、現在のスタックの内容を確認する必要があります。ok プロンプトが現れるごとにスタックの内容を表示するには、次のように入力します。
ok showstack 44 7 ok 8 47 7 8 ok showstack ok |
一番上のスタック項目は、ok プロンプトの直前に、リストの最後の項目として常に表示されます。上記の例では、一番上のスタック項目は 8 です。
前に showstack を実行している場合は、もう一度 noshowstack と入力すると、各プロンプトの前のスタック表示が削除されます。
この章のいくつかの例では showstack を有効にしています。それらの例では、各 ok プロンプトの直前にそのときのスタックの内容が表示されています。それらの例は、スタックの内容が表示される点を除けば、showstack を有効にしてない場合と同じです。
数値変数を必要とするほとんどすべてのワードは、それらの変数をスタックの一番上から取り出します。また、返されるどの値も、通常、スタックの一番上に残され、別のコマンドで表示したり、「消費」する (つまり演算などに使ってスタックから削除する) ことができます。たとえば、+ という Forth ワードは、スタックから 2 つの数値を削除し、それらを加算し、結果をスタックに残します。次の例では、演算はすべて 16 進で行われます。
44 7 8 ok + 44 f ok + 53 ok |
2 つの値が加算されると、結果がスタックの一番上に乗せられます。Forth ワードの . は一番上のスタック項目を削除し、その値を画面に表示します。次の例を参照してください。
53 ok 12 53 12 ok . 12 53 ok . 53 ok (ここではスタックは空) ok 3 5 + . 8 ok (ここではスタックは空) ok . Stack Underflow ok |
スタックダイアグラム規則に従うコーディング形式では、わかりやすいように Forth ワードの定義ごとに、それぞれの最初の定義行に ( -- )の形式のスタックダイアグラムを表記する必要があります。スタックダイアグラムは、ワードを実行するとスタックがどうなるかを指定するものです。
-- の左側に置かれる項目は、 スタックから消費 (つまり削除) され、そのワードの演算に使用されるスタック項目を示します。-- の右側に置かれる項目は、ワードの実行の終了後にスタックに残されるスタック項目を示します。 たとえば、ワード + のスタックダイアグラムは ( nu1 nu2 -- sum ) であり、ワード. のスタックダイアグラムは ( nu -- ) です。したがって、+ は 2 つの数値 (nu1 と nu2) を削除し、次にそれらの和 (sum) をスタックに残します。ワード . はスタックの一番上の数値 (nu) を削除し、それを表示します。
スタックの内容に影響しないワード (showstack や decimal など) のスタックダイアグラムは ( -- ) になります。
場合によっては、ワードのすぐ後に別のワード、またはほかのテキストが必要なことがあります。たとえば、see は、 see thisword ( -- ) という形式で使用されます。
スタック項目は、正しい使い方がわかるように、一般的に (意味を表すような) 説明的名前を使用して書きます。このマニュアルで使用するスタック項目の省略表記については、表 4-1 を参照してください。
表 4-1 スタック項目の表記法
表記 |
説明 |
---|---|
| |
前後に空白文字を入れて表示される代替スタック結果。たとえば、( input -- addr len false | result true )。 |
| |
前後に空白文字なしで表示される代替スタック項目。たとえば、( input -- addr len | 0 result )。 |
??? |
未知のスタック項目 (1 つまたは複数)。 |
... |
未知のスタック項目 (1 つまたは複数)。スタックコメントの両側に使用した場合は、両側に同じスタック項目があることを意味します。 |
< > <space> |
空白区切り文字。先行空白文字は無視されます。 |
a-addr |
可変境界アドレス。 |
addr |
メモリーアドレス (一般的に仮想アドレス)。 |
addr len |
メモリー領域のアドレスと長さ。 |
byte bxxx |
8 ビット値 (32 ビットワードの下位バイト)。 |
char |
7 ビット値 (下位バイト)。上位ビットは不定。 |
cnt len size |
カウント値または長さ。 |
dxxx |
倍 (拡張) 精度数。2 スタック項目 - スタックの一番上の上位 quadlet (32 ビット)。 |
<eol> |
行末区切り文字。 |
false |
0 (false フラグ)。 |
ihandle |
パッケージのインスタンスのポインタ。 |
n n1 n2 n3 |
通常の符号付き値 (32 ビット) |
nu nu1 |
符号付きまたは符号なしの値 (32 ビット) |
<nothing> |
ゼロスタック項目。 |
phandle |
パッケージのポインタ。 |
phys |
物理アドレス (実際のハードウェアアドレス)。 |
phys.lo phys.hi |
物理アドレスの下位/上位セル。 |
pstr |
パックされた文字列。 |
quad qxxx |
quadlet (32 ビット値)。 |
qaddr |
quadlet (32 ビット値) 境界のアドレス。 |
{text} |
省略可能なテキスト。省略した場合は、デフォルト操作が行われます。 |
"text<delim>" |
入力バッファーテキスト。コマンドの実行時に構文解析されます。テキスト区切り文字を <> で囲みます。 |
[text<delim>] |
同じ行上のコマンドのすぐ後のテキスト。ただちに構文解析されます。テキスト区切り文字は <> で囲みます。 |
true |
-1 (true フラグ)。(真) |
uxxx |
符号なしの値、正の値 (32 ビット)。 |
virt |
仮想アドレス (ソフトウェアが使用するアドレス)。 |
waddr |
doublet (16 ビット) 境界のアドレス。 |
word wxxx |
doublet (16 ビット値、32 ビットワードの下位 2 バイト)。 |
x x1 |
任意のスタック項目。 |
x.lo x.hi |
データ項目の最下位/最上位ビット。 |
xt |
実行トークン。 |
xxx? |
フラグ。名前は用途を示します (たとえば、done? ok? error?)。 |
xyz-str xyz-len |
パックされない文字列のアドレスと長さ。 |
xyz-sys |
制御フロー用スタック項目。実装に依存します。 |
( C: -- ) |
コンパイルスタックダイアグラム。 |
( -- ) ( E: -- ) |
実行スタックダイアグラム。 |
( R: -- ) |
復帰スタックダイアグラム。 |
スタック操作用のコマンド (表 4-2 で説明) では、スタック上の項目の追加、削除、並べ替えができます。
表 4-2 スタック操作コマンド
コマンド |
スタックダイアグラム |
説明 |
---|---|---|
-rot |
( x1 x2 x3 -- x3 x1 x2 ) |
3 つのスタック項目を逆方向に回転します。 |
>r |
( x -- ) (R: -- x ) |
スタック項目を復帰スタックに転送します。 (使用には注意が必要です。) |
?dup |
( x -- x x | 0 ) |
一番上のスタック項目がゼロ以外の場合、複製します。 |
2drop |
( x1 x2 -- ) |
スタックから 2 つの項目を削除します。 |
2dup |
( x1 x2 -- x1 x2 x1 x2 ) |
2 つのスタック項目を複製します。 |
2over |
( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 ) |
初めから 2 つのスタック項目をコピーします。 |
2rot |
( x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2 ) |
3 対のスタック項目を回転します。 |
2swap |
( x1 x2 x3 x4 -- x3 x4 x1 x2 ) |
2 対のスタック項目を入れ換えます。 |
3drop |
( x1 x2 x3 -- ) |
スタックから 3 つの項目を削除します。 |
3dup |
( x1 x2 x3 -- x1 x2 x3 x1 x2 x3 ) |
3 つのスタック項目を複製します。 |
clear |
( ??? -- ) |
スタックを空にします。 |
depth |
( -- u ) |
スタック上の項目数を返します。 |
drop |
( x -- ) |
一番上のスタック項目を削除します。 |
dup |
( x -- x x ) |
一番上のスタック項目を複製します。 |
nip |
( x1 x2 -- x2 ) |
2 番目のスタック項目を削除します。 |
over |
( x1 x2 -- x1 x2 x1 ) |
2 番目のスタック項目をスタックの一番上にコピーします。 |
pick |
( xu ... x1 x0 u -- xu ... x1 x0 xu ) |
u 番目のスタック項目をコピーします (1 pick = over)。 |
r> |
( -- x ) ( R: x -- ) |
復帰スタック項目をスタックに転送します。(使用には注意が必要です。) |
r@ |
( -- x ) ( R: x -- x ) |
復帰スタックの一番上をスタックにコピーします。 |
roll |
( xu ... x1 x0 u -- xu-1 ... x1 x0 xu ) |
u 個のスタック項目を回転します (2 roll = rot)。 |
rot |
( x1 x2 x3 -- x2 x3 x1 ) |
3 つのスタック項目を回転します。 |
swap |
( x1 x2 -- x2 x1 ) |
一番上の 2 つのスタック項目を入れ換えます。 |
tuck |
( x1 x2 -- x2 x1 x2 ) |
一番上のスタック項目を 2 番目の項目の下にコピーします。 |
代表的なスタック操作の用途は、次の例に示すように、すべてのスタック項目を保持しておきながら、一番上のスタック項目を表示することです。
5 77 ok dup (一番上のスタック項目を複製) 5 77 77 ok . (一番上のスタック項目を削除し、表示) 77 5 77 ok |