Forth のスタックは、数値情報の一時的保持用の後入れ先出し型 (LIFO) バッファーです。これを積み重ねられた本と考えてみてください。その場合、最後に置いた、つまり本の積み重ねの一番上に乗せた本から先に取ることになります。Forth を使用するには、スタックを理解することが不可欠です。
スタックに数値を入れる (一番上に乗せる) には、単にその値を入力します。
ok 44 (値 44 がスタックの一番上に乗る) ok 7 (値 7 がスタックの一番上に乗り、44はそのすぐ下になる) ok |
スタックの内容は通常は表示されません。しかし、希望する結果を得るためには、現在のスタックの内容を確認する必要があります。ok プロンプトが現れるごとにスタックの内容を表示することができますが、それには、次のように入力します。
ok showstack 44 7 ok 8 44 7 8 ok noshowstack 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 )
です。この場合、+ は 2 つの数値 (nu1 nu2-- sum ) です。この場合、+ は 2 つの数値 (nu1 と nu2) をスタックから削除し、それらの和 (sum) をスタックに残します。もう 1 つの例として、ワード . のスタックダイアグラム
(nu -- )
があります。この場合、ワード . はスタックの一番上の数値 (nu) を削除し、それを表示します。
スタックの内容に影響しないワード (showstack や decimal など) のスタックダイアグラムは (-- ) になります。
場合によっては、コマンド行のワードのすぐ後に別のワード、または他のテキストが必要なことがあります。たとえば、ワード see は
see thisword (-- )
という形式で使用されます。
スタック項目は、正しい使い方がわかりやすいように、一般的に (意味を表すような) 説明的名前を使用して書きます。本書で使用するスタック項目の省略表記については、表 4-2を参照してください。
表 4-2 スタック項目の表記法
表記 |
説明 |
---|---|
| |
前後に空白文字を入れて表示される代替スタック結果。たとえば、( input -- addr len false | result true )。 |
??? |
未知のスタック項目 (1 つまたは複数)。 |
未知のスタック項目 (1 つまたは複数)。スタックコメントの両側に使用した場合は、両側に同じスタック項目があることを意味します。 |
|
< > <space> |
空白区切り文字。先行空白文字は無視されます。 |
a-addr |
可変境界アドレス。 |
addr |
メモリーアドレス (一般的に仮想アドレス)。 |
addr len |
メモリー領域のアドレスと長さ。 |
byte bxxx |
8 ビット値 (1 セル中の下位バイト)。 |
char |
7 ビット値 (1 セル中の下位バイト)。最上位ビットは不定。 |
cnt |
カウント値。 |
len |
長さ。 |
size |
カウント値または長さ。 |
dxxx |
倍 (拡張) 精度数。2 セルで、スタックの上部には、最上位のセルが置かれる。quadlet (32 ビット)。 |
<eol> |
行末区切り文字。 |
false |
0 (false フラグ)。 |
n n1 n2 n3 |
通常の符号付き 1 セルの値。 |
nu nu1 |
符号付きまたは符号なしの 1 セルの値。 |
<nothing> |
ゼロスタック項目。 |
o o1 o2 oct1 oct2 |
Octlet (符号付き 64 ビット値)。 |
oaddr |
Octlet (64 ビット) 境界のアドレス。 |
octlet |
8 バイト数値。 |
phys |
物理アドレス (実際のハードウェアアドレス)。 |
phys.lo phys.hi |
物理アドレスの下位/上位セル。 |
pstr |
パックされた文字列。 |
quad qxxx |
Quadlet (32 ビット値、1 セル中の下位 4 バイト) |
qaddr |
Quadlet (32 ビット値) 境界のアドレス。 |
true |
-1 (true フラグ)。(真) |
uxxx |
1 セル、符号なし 32 ビット値、正の値 (32 ビット)。 |
virt |
仮想アドレス (ソフトウェアが使用するアドレス)。 |
waddr |
Doublet (16 ビット) 境界のアドレス。 |
word wxxx |
Doublet (16 ビット値、1 セル中の下位 2 バイト)。 |
x x1 |
任意の 1 セルのスタック項目。 |
x.lo x.hi |
データ項目の下位/上位ビット |
xt |
実行トークン。 |
xxx? |
フラグ。名前は用途を示します (たとえば、 done? ok? error?)。 |
xyz-str xyz-len |
パックされない文字列のアドレスと長さ。 |
xyz-sys |
制御フロー用スタック項目。実装に依存します。 |
( C: -- ) |
コンパイルスタックダイアグラム。 |
( -- )( E: -- ) |
実行スタックダイアグラム。 |
( R: -- ) |
復帰スタックダイアグラム。 |
スタック操作用のコマンド (表 4-3で説明) では、スタック上の項目の追加、削除、並べ替えができます。
表 4-3 スタック操作コマンド
代表的なスタック操作の用途は、次の例に示すように、すべてのスタック項目を保持しておきながら、一番上のスタック項目を表示することです。
5 77 ok dup (一番上のスタック項目を複製) 5 77 77 ok . (一番上のスタック項目を削除し、表示) 77 5 77 ok |