OpenBoot 3.x コマンド・リファレンスマニュアル

スタック

Forth のスタックは、数値情報の一時的保持用の後入れ先出し型 (LIFO) バッファーです。これを積み重ねられた本と考えてみてください。その場合、最後に置いた、つまり本の積み重ねの一番上に乗せた本から先に取ることになります。Forth を使用するには、スタックを理解することが不可欠です。

スタックに数値を入れる (一番上に乗せる) には、単にその値を入力します。


ok 44  (値 44 がスタックの一番上に乗る)
ok 7 (値 7 がスタックの一番上に乗り、44 はそのすぐ下になる)
ok 

スタックの内容の表示

スタックの内容は通常は表示されません。しかし、希望する結果を得るためには、現在のスタックの内容を確認する必要があります。ok プロンプトが現れるごとに スタックの内容を表示することができますが、それには、次のように入力します。


ok showstack
44 7 ok 8
44 7 8ok 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) をスタックに残します。もう 1 つの例として、ワード . のスタックダイアグラム

( nu -- )

があります。この場合、ワード . はスタックの一番上の数値 (nu) を削除し、それを表示します。

スタックの内容に影響しないワード (showstackdecimal など) のスタックダイアグラムは ( -- ) になります。

場合によっては、コマンド行のワードのすぐ後に別のワード、または他のテキストが必要なことがあります。たとえば、ワード 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 スタック操作コマンド

コマンド  

スタックダイアグラム 

説明 

clear

( ??? -- ) 

スタックを空にします。 

depth

( ... -- ... u ) 

スタック上の項目数を返します。 

drop

( x -- ) 

一番上のスタック項目を削除します。 

2drop

( x1 x2 -- ) 

スタックから 2 つの項目を削除します。 

3drop

( x1 x2 x3 -- ) 

スタックから 3 つの項目を削除します。 

dup

( x -- x x )  

一番上のスタック項目を複製します。 

2dup

( x1 x2 -- x1 x2 x1 x2 ) 

2 つのスタック項目を複製します。 

3dup

( x1 x2 x3 -- x1 x2 x3 x1 x2 x3 ) 

3 つのスタック項目を複製します。 

?dup

( x -- x x | 0 ) 

一番上のスタック項目がゼロ以外の場合、複製します。 

nip

( x1 x2 -- x2 ) 

2番目のスタック項目を削除します。 

over

( x1 x2 -- x1 x2 x1 ) 

2 番目のスタック項目をスタックの一番上にコピーします。 

2over

( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 ) 

初めから 2 つのスタック項目をコピーします。 

pick

( xu ... x1 x0 u -- xu ... x1 x0 xu ) 

u 番目のスタック項目をコピーします (1 pick = over)。

>r

( x -- ) (R: -- x ) 

スタック項目を復帰スタックに転送します。 

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 つのスタック項目を逆方向に回転します。 

-rot

( x1 x2 x3 -- x3 x1 x2 ) 

3 つのスタック項目を逆方向に回転します。 

2rot

( x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2 ) 

3 対のスタック項目を回転します。 

swap

( x1 x2 -- x2 x1 ) 

一番上の 2 つのスタック項目を入れ換えます。 

2swap

( x1 x2 x3 x4 -- x3 x4 x1 x2 ) 

2 対のスタック項目を入れ換えます。 

tuck

( x1 x2 -- x2 x1 x2 ) 

一番上のスタック項目を 2 番目の項目の下にコピーします。 

代表的なスタック操作の用途は、次の例に示すように、すべてのスタック項目を保持しておきながら、一番上のスタック項目を表示することです。


5 77 ok dup   (一番上のスタック項目を複製)  
5 77 77 ok .  (一番上のスタック項目を削除し、表示) 
77 
5 77 ok