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

第 4 章 Forth ツールの使用方法

この章では、OpenBoot に実装されている Forth の概要を説明します。Forth プログラミング言語に詳しい読者も、この章の例を確認してください。これらの例には、OpenBoot に関連する特有の情報が含まれています。

OpenBoot に含まれる Forth のバージョンは、ANS Forth に準拠しています。付録 E 「Forth ワードリファレンス」 に全コマンドのリストが載せてあります。SBus デバイス用 OpenBoot FCode プログラムを書くための専用のワードについては、『Writing FCode 2.x Programs』マニュアルに説明されています。


注 -

この章では、読者はユーザーインタフェースの起動、終了手順を知っているものとしています。ok プロンプトで入力したコマンドのためにシステムがハングアップし、キー入力操作で回復できない場合は、正常動作に復帰させるために電源再投入を行う必要が生じることもあります。


Forth コマンド

Forth のコマンド構造は非常に単純です。Forth のコマンドは、Forth ワードとも呼ばれますが、印刷可能な文字、たとえば、英字、数字、句読記号の任意の組み合わせです。正しいワードの例を次に示します。

@

dump

.

0<

+

probe-pci

probe-scsi コマンドとして認識されるためには、Forth ワードはそれぞれの間を 1 つまたはそれ以上の空白文字 (ブランク) で分離する必要があります。どのコマンド行の終わりで Return キーを押しても、そこまで入力したコマンドが実行されます。(この章に示すすべての例で、行の終わりでは Return が押されるものとしています。)

1 コマンド行に複数のワードを入力できます。1 行上の複数のワードは、左から右に向かって、つまり入力順に 1 つ 1 つ実行されます。たとえば、次の例の


ok testa testb testc 
ok 

は次の 3 行と同じです。


ok testa 
ok testb 
ok testc 
ok 

OpenBoot では、大文字と小文字の区別はありません。したがって、testaTESTATesTa はすべて同じコマンドを起動します。しかし、習慣によりコマンドは小文字で書きます。

コマンドによっては (たとえば、dump または words)、大量の出力を生成するものがあります。そのようなコマンドは、q 以外の任意のキーを押して中断できます。(q を押した場合は、出力は一時停止でなく強制終了されます。) コマンドを中断すると、出力は一時的に停止され、次のメッセージが表示されます。


More [<space>,<cr>,q] ? 

これに対して、スペースバー (<space>) を押して出力を再開するか、Return (<cr>) キーを押して 1 行出力し、再び休止するか、または q を入力してコマンドを強制終了します。出力を複数ページ生成する場合は、システムは自動的に各ページの終わりに上に示したプロンプトを表示します。

数値の用法

数値は、たとえば 55 や -123 など、その値をキーボードで入力します。Forth は整数しか受け入れません。分数値 (たとえば、2/3) は入力できません。数値の終わりにピリオドを入力すると、それが倍精度であることを意味します。数値のなかにピリオド、コンマを埋め込んでも無視されます。したがって、5.77 は 577 と解釈されます。表記の規約では、区切り記号は通常 4 桁おきに使用します。数値は、1 つまたはそれ以上の空白文字を使用してワードや別の数値と区切ってください。

OpenBoot は 32 ビット整数の数値演算を行います。別に指定がないかぎり、数値はすべて 32 ビットです。

OpenBoot では 16 進の (変換) 基数を使用するよう奨励されていますが、これは必須ではありません。したがって、コードが特定の基数に依存する場合は、正しく演算されるために、そのような基数を設定する必要があります。

演算する数値の基数は octaldecimalhex といったコマンドを使用して変更できます。これらのコマンドは、以降の数値の入出力をそれぞれ 8、10、16 を基数として行わせます。

たとえば、10 進で演算するには、次のように入力します。


ok decimal 
ok 

16 進に変更するには、次のように入力します。


ok hex 
ok 

現在使用されている基数を知る 2 つの単純な方法を次に示します。


ok 10 .d
16
ok 10 1- .
f
ok 

上記の画面に表示されている 16f は、16 進で演算が行われることを示しています。109 が表示される場合は、10 を基数としていることを意味します。87 であれば、8 進を示します。

スタック

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 つの数値 (nu1nu2) を削除し、次にそれらの和 (sum) をスタックに残します。ワード . はスタックの一番上の数値 (nu) を削除し、それを表示します。

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

場合によっては、ワードのすぐ後に別のワード、またはほかのテキストが必要なことがあります。たとえば、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

カスタム定義の作成

Forth は、新しいコマンドワードの利用者定義を作成するための簡単な手段を提供します。表 4-3 に、利用者定義作成用の Forth ワードを示します。

表 4-3 コロン定義ワード

コマンド 

スタックダイアグラム 

説明 

: new-name

( -- ) 

ワード new-name の新しいコロン定義を開始します。

;  

( -- ) 

コロン定義を終了します。 

新しいコマンドの定義は、: を用いて定義することから、コロン定義と呼ばれます。たとえば、任意の 4 つの数値を加算し、結果を表示する新しいワード add4 を作成するとします。定義は、たとえば次のように作成できます。


ok : add4  + + + .  ;
ok 

; (セミコロン) は、(+ + + .) の操作を行わせるように add4 を定義する定義の終わりを示します。3 つの加算演算子 (+) は 4 つのスタック項目を 1 つの和に変えてスタックに残します。次に . はその結果を削除し、表示します。次に例を示します。


ok 1 2 3 3 + + + .
9
ok 1 2 3 3 add4
9
ok 

これらの定義はローカルメモリーに格納されます。つまり、システムをリセットすると消去されます。よく使う定義を保存するには、(オペレーティングシステムのもとでテキストエディタを使用して、または NVRAMRC エディタを使用して) テキストファイルにそれらの定義を保存します。このテキストファイルは、以降、必要に応じて読み込めます。(ファイルの読み込みについての詳細は、第 5 章「プログラムの読み込みと実行」を参照してください。)

ユーザーインタフェースから定義を入力すると、: (コロン) を入力してから ; (セミコロン) を入力するまで、ok プロンプトが ] (右角括弧) プロンプトになります。たとえば、add4 の定義は次のように入力できます。


ok : add4 
]  + + + 
]  . 
]  ; 
ok 

テキストファイル内に作成するすべての定義には、そのスタック効果がない場合 (--) であっても、それぞれに、定義が表すスタック効果のダイアグラムが必要です。スタックダイアグラムは、ワードの正しい使い方を示すのできわめて重要です。さらに、複雑な定義内にはわかりやすいスタックコメントを使用してください。それによって、実行のフローを容易に追跡できます。たとえば、add4 を作成するには、次のように定義できます。


: add4  ( n1 n2 n3 n4 -- )  + + + .  ; 

または、次のようにも定義できます。


: add4  ( n1 n2 n3 n4 -- )
   + + +  ( sum )
   .
; 


注 -

「(」(左側括弧) は、それ以降「)」 (右側括弧) までのテキストを無視することを意味します。ほかのすべての Forth ワードと同様に、左側括弧の右側には 1 つまたはそれ以上の空白文字が必要です。


演算機能の使用方法

表 4-4 に示すコマンドは、データスタック上の項目に対する基本演算コマンドです。

表 4-4 演算機能

コマンド 

スタックダイアグラム 

説明 

+

( nu1 nu2 -- sum ) 

nu1 + nu2 の加算を行います。

-

( nu1 nu2 -- diff ) 

nu1 - nu2 の減算を行います。

*

( nu1 nu2 -- prod ) 

nu1 * nu2 の乗算を行います。

/

( n1 n2 -- quot ) 

n1n2 で割ります。剰余は捨てられます。

/mod

( n1 n2 -- rem quot ) 

n1 / n2 の剰余と商。

<<

( x1 u -- x2 ) 

lshift の同義語。

>>

( x1 u -- x2 ) 

rshift の同義語。

>>a

( x1 u -- x2 ) 

x1u ビット右に算術シフトします。

*/

( n1 n2 n3 -- quot ) 

n1 * n2 / n3

*/mod

( n1 n2 n3 -- rem quot ) 

n1 * n2 / n3 の剰余と商。

1+

( nu1 -- nu2 ) 

1 を足します。 

1-

( nu1 -- nu2 ) 

1 を引きます。 

2*

( nu1 -- nu2 ) 

2 を掛けます。 

2+

( nu1 -- nu2 ) 

2 を足します。 

2-

( nu1 -- nu2 )  

2 を引きます。 

2/

( nu1 -- nu2 ) 

2 で割ります。 

abs

( n -- u ) 

絶対値 

aligned

( n1 -- n1 | a-addr) 

n1 を次の 4 の整数倍に切り上げます。

and

( n1 n2 -- n3 ) 

ビット単位の論理積。 

bounds

( startaddr len -- endaddr startaddr ) 

do ループ用に startaddr lenendaddr startaddr に変換します。

bljoin

( b.low b2 b3 b.hi -- quad ) 

4 バイトを結合して 32 ビットの 4 バイトワードを作ります。 

bwjoin

( b.low b.hi -- word ) 

2 バイトを結合して 16 ビットのワードを作ります。 

d+

(d1 d2 -- d.sum ) 

2 つの 64 ビット数値の加算を行います。 

d-

(d1 d2 --d.diff ) 

2 つの 64 ビット数値の減算を行います。 

even

( n -- n | n+1 ) 

最も近い偶数の整数 >= n に丸めます。

fm/mod

( d n -- rem quot ) 

dn で割ります。

invert

( x1 -- x2 ) 

x1 の全ビットを反転します。

lbflip

( quad1 -- quad2 ) 

32 ビットの 4 バイトワード内のバイトをスワップします。 

lbsplit

( quad -- b.low b2 b3 b.hi ) 

32 ビットの 4 バイトワードを 4 バイトに分割します。 

lwflip

( quad1 -- quad2 ) 

32 ビットの 4 バイトワードの半分をスワップします。 

lwsplit

( quad -- w.low w.hi ) 

32 ビットの 4 バイトワードを 2 つの 16 ビットワードに分割します。 

lshift

( x1 u -- x2 ) 

x1u ビット左シフトし、下位ビットにゼロを埋め込みます。

max

( n1 n2 -- n3 ) 

n1n2 の大きいほうの値を n3 とします。

min

( n1 n2 -- n3 ) 

n1n2 の小さいほうの値を n3 とします。

mod

( n1 n2 -- rem ) 

n1 / n2 の剰余を計算します。

negate

( n1 -- n2 ) 

n1 の符号を変更します。

not

( x1 -- x2 ) 

invert の同義語。

or

( n1 n2 -- n3 ) 

ビット単位の論理和。 

rshift

( x1 u -- x2 ) 

x1u ビット右シフトし、上位ビットにゼロを埋め込みます。

s>d

( n1 -- d1 ) 

数値を倍精度数に変換します。 

sm/rem

( d n -- rem quot ) 

d を n で割ります。対称除算。

u2/

( x1 -- x2 ) 

1 ビット右へ論理シフトし、上位ビットにゼロをシフトします。 

u*

(u1 u2 -- uprod ) 

符号なしの 2 つの数値を乗算し、符号なしの積を生じます。 

u/mod

( u1 u2 -- urem uquot ) 

符号なし 32 ビット数値を符号なし 32 ビット数値で割り、32 ビットの剰余と商を生じます。 

um*

( u1 u2 -- ud ) 

符号なしの 2 つの 32 ビット数値を乗算し、符号なし倍精度数の積を生じます。 

um/mod

( ud u -- urem uprod ) 

ud を u で割ります。

wbflip

( word1 -- word2 ) 

16 ビットワード内のバイトをスワップします。 

wbsplit

( word -- b.low b.hi ) 

16 ビットワードを 2 バイトに分割します。 

wljoin

( w.low w.hi -- quad ) 

2 ワードを結合して 4 バイトワードを作ります。 

xor

( x1 x2 --x3 ) 

ビット単位排他的の論理和。 

メモリーのアクセス

メモリーアクセスするユーザーインタフェースはメモリー内容の確認および設定用のコマンドを備えています。次の操作はユーザーインタフェースを使用して行います。

メモリー演算子を使用すると、任意のメモリー位置からの読み取り、任意のメモリー位置への書き込みが行えます。以降の例に示すメモリーアドレスはすべて仮想アドレスです。

8 ビット、16 ビット、32 ビットのさまざまな操作ができます。一般的に、c (文字) という接頭辞は 8 ビット (1 バイト) の操作を示し、w (ワード) という接頭辞は 16 ビット (2 バイト) の操作を示し、l (quadlet) という接頭辞は 32 ビット (4 バイト) の操作を示します。


注 -

l は、場合によっては、数字の 1 との混同を避けるために大文字で示すことがあります。


waddrqaddraddr64 は境界の制約をもつアドレスを示します。たとえば、qaddr は 32 ビット (4 バイト) 境界を示し、したがってそのアドレス値は次の例に示すように 4 で割り切れなければなりません。


ok 4028 L@ 
ok 4029 L@ 
Memory address not aligned 
ok 

OpenBoot に実装されている Forth インタプリタはできるだけ ANS の Forth 標準に準拠しています。明示的に 16 ビットまたは 32 ビットを取り出す場合は、@ の代わりにそれぞれ w@ または L@ を使用してください。そのほかのメモリーやデバイスレジスタへのアクセスコマンドもこの規則に従います。

表 4-5 にメモリーアクセス用のコマンドを示します。

表 4-5 メモリーアクセスコマンド

コマンド 

スタックダイアグラム 

説明 

!

( x a-addr -- ) 

数値を a-addr に格納します。

+!

( nu a-addr -- ) 

nua-addr に格納されている数値に加算します。

<w@

( waddr -- n ) 

doublet wwaddr から符号拡張して取り出します。

@

( a-addr --x ) 

数値を a-addr から取り出します。

2!

( x1 x2 a-addr -- ) 

2 つの数値を a-addr に格納します。x2 が下位アドレス。

2@

( a-addr -- x1 x2 )  

2 つの数値を a-addr から取り出します。x2 が下位アドレス。

blank

( addr len -- ) 

addr からの len バイトを空白文字 (10 進の 32) に設定します。

c!

(byte addr -- ) 

byteaddr に格納します。

c@

( addr -- byte ) 

byteaddr から取り出します。

cmove

( addr1 addr2 u -- ) 

addr1 から addr2 に、下位バイトから先に、u バイトをコピーします。

cmove>

( addr1 addr2 u -- ) 

addr1 から addr2 に、上位バイトから先に、u バイトをコピーします。

cpeek

( addr -- false | byte true ) 

addr の 1 バイトを取り出します。アクセスが成功した場合はそのデータと true を返し、読み取りエラーが発生した場合は false を返します。

cpoke

( byte addr -- okay? ) 

byteaddr に格納します。アクセスが成功した場合は true を返し、書き込みエラーが発生した場合はfalse を返します。

comp

( addr1 addr2 len -- diff? ) 

2 つのバイト配列を比較します。 両配列が等しい場合は diff? = 0、異なる最初のバイトにおいて、addr1 の文字列の方が小さい場合は diff? =-1、それ以外の場合は diff? = 1 になります。

dump

( addr len -- ) 

addr から len バイトのメモリを表示します。

erase

( addr len -- ) 

addr から len バイトのメモリを 0 に設定します。

fill

( addr len byte -- ) 

addr から len バイトのメモリを値 byte に設定します。

l!

( n qaddr -- ) 

quadlet qqaddr に格納します。

l@

( qaddr -- quad ) 

quadlet qqaddr から取り出します。

lbflips

( qaddr len -- ) 

指定された領域の各 quadlet 内のバイトを逆に並べ替えます。 

lwflips

( qaddr len -- ) 

指定された領域の各 quadlet 内の doublet をスワップします。 

lpeek

( qaddr -- false | quad true ) 

32 ビット数値を qaddr から取り出します。アクセスが成功した場合はそのデータと true を返し、読み取りエラーが発生した場合は false を返します。

lpoke

( quad qaddr -- okay? ) 

32 ビットの数値を qaddr に格納します。アクセスが成功した場合は true を返し、書き込みエラーが発生した場合は false を返します。

move

( src-addr dest-addr len -- ) 

src-addr から dest-addrlen バイトをコピーします。

off

( a-addr -- ) 

a-addrfalse を格納します。

on

( a-addr -- ) 

a-addrtrue を格納します。

unaligned-l!

( quad addr -- ) 

quadlet q を任意の境界に格納します。(境界は問われません。)

unaligned-l@

( addr -- quad ) 

quadlet q を任意の境界で取り出します。(境界は問われません。)

unaligned-w!

( w addr -- ) 

doublet w を任意の境界に格納します。(境界は問われません。)

unaligned-w@

( addr -- w ) 

doublet w を任意の境界で取り出します。(境界は問われません。)

w!

( w waddr -- ) 

doublet wwaddr に格納します。

w@

( waddr -- w) 

doublet wwaddr から取り出します。

wbflips

( waddr len -- ) 

指定された領域の各 doublet 内のバイトをスワップします。 

wpeek

( waddr -- false | w true ) 

16 ビットの数値を waddr から取り出します。アクセスが成功した場合はそのデータと true を返し、読み取りエラーが発生した場合は false を返します。

wpoke

( w waddr -- okay? ) 

16 ビットの数値を waddr に格納します。アクセスが成功した場合は true を返し、書き込みエラーが発生した場合は false を返します。

dump コマンドは特に便利です。このコマンドは、メモリーの領域をバイト値、ASCII 値の両方で表示します。次の例は、仮想アドレス仮想アドレス 10000 からの 20 バイトを表示します。さらに、特定のメモリー位置に読み書きする方法も示しています。


ok 10000 20 dump   (仮想アドレス 10000 からの 20 バイトを表示) 
      ¥/ 1  2  3  4  5  6  7   8  9  a  b  c  d  e  f  v123456789abcdef 
10000 05 75 6e 74 69 6c 00 40  4e d4 00 00 da 18 00 00 .until.@NT..Z...
10010 ce da 00 00 f4 f4 00 00  fe dc 00 00 d3 0c 00 00 NZ..tt..‾¥..S...
ok 22 10004 c!   (メモリー位置 10004 の 8 ビットバイトを 22 に変更) 
ok

(たとえば、@ を使用して) 無効なメモリー位置をアクセスしようとした場合は、処理はただちに終了し、PROM が Data Access Exception または Bus Error などのエラーメッセージを表示します。(注: 数字は 16 進数で記述されています。)

表 4-6 にメモリー割り当て用のコマンドを示します。

表 4-6 メモリー割り当てコマンド

コマンド 

スタックダイアグラム 

説明 

alloc-mem

( size -- virt ) 

size バイトの空きメモリーを割り当てます。割り当てた仮想アドレスを返します。

free-mem

( virt size -- ) 

alloc-mem で割り当てられていたメモリーを開放します。

free-virtual

( virt size -- ) 

memmap で作成されていた割り当てを取り消します。

次の画面は alloc-memfree-mem の使用例です。

memmap の使用例を次に示します。


ok 200.0000 sbus 1000 memmap ( virt ) 
ok 

SBus デバイスのマップ

ここでは、システムに依存するデバイスアドレスを知る必要なしに、ok プロンプトから SBus デバイスを割り当てる一般的な方法を示します。この方法は、SBus デバイス上に有効な FCode PROM があるかどうかには依存しません。2.0 またはそれ以降のバージョンのすべての OpenBoot システムで有効です。


ok " /sbus"  select-dev
ok (offset) (slot#) (size) map-in ( virt )
ok

たとえば、システムのスロット番号 3 のデバイスの FCode PROM の内容を調べるには、次のように入力します。


ok " /sbus"  select-dev
ok 0 3 1000 map-in  .s
ffed3000
ok dup 20 dump
(FCode PROM の内容が最初の 20 バイト表示されます)
ok

この方法は、多少変更することができます。

  1. システムによっては、システムの SBus のパス名が異なることがあります。たとえば、" /iommu/sbus" (Sun4m の場合)や " /io-unit/sbi" (Sun4d の場合) です。ok プロンプトで show-devs コマンド (すべてのシステムデバイスをリストします) を使用するのが、正しいパスを知る 1 つの方法です。

  2. スタックに (オフセットサイズを) 直接入れる方法は、将来のシステムの一般的ケースでは有効である場合とそうでない場合があります。問題が生じた場合は、さらに一般的な手段として、次の方法を試みてください。


    ok " /sbus" select-dev
    ok " 3,0: decode-unit  ( offset space )
    ok 1000 map-in         ( virt )
    ok

ワード定義の使用方法

辞書には用意されているすべての Forth コマンドが含まれています。ワード定義を使って新しい Forth コマンドを作成します。

ワード定義は 2 つのスタックダイアグラムを必要とします。最初のダイアグラムでは、新しいコマンドを作成するときのスタック効果を示します。第 2番目の (Usage:) ダイアグラムはそのコマンドが後で実行されるときのスタック効果を示します。

表 4-7 に辞書エントリを作成するためのワード定義を示します。

表 4-7 ワード定義

コマンド 

スタックダイアグラム 

説明 

: name

( -- ) Usage: ( ??? -- ? ) 

新しいコロン定義の作成を開始します。 

;  

( -- ) 

新しいコロン定義の作成を終了します。 

alias new-name old-name

( -- ) Usage: ( ??? -- ? ) 

old-name と同じ操作をする new-name を作成します。

buffer: name

( size -- ) Usage: ( -- a-addr )  

指定された配列を一時記憶領域に作成します。 

constant name

( n -- ) Usage: ( -- n )  

定数 (たとえば、3 constant bar) を定義します。

2constant name

( n1 n2 -- ) Usage: ( -- n1 n2 )  

2 つの数値の定数を定義します。 

create name

( -- ) Usage: ( -- waddr )  

汎用ワード定義。 

defer name

( -- ) Usage: ( ??? -- ? )  

フォワードリファレンス、または実行トークンを使用する実行ベクトル用のワードを定義します。 

does>

( -- waddr )  

ワード定義のための実行時の節を開始します。 

field name

( offset size -- offset+size ) Usage: ( addr -- addr+offset ) 

指定されたオフセットポインタを作成します。 

struct

( -- 0 ) 

field の作成に備えて初期化します。

value name

( n -- ) Usage: ( -- n )  

指定された、変更可能な 32 ビットの数値を作成します。 

variable name

( -- ) Usage: ( -- waddr )  

変数を定義します。 

ワード定義 constant を使用して、値が変わらない名前を作成できます。単純なコロン定義 : foo 22 ; でも同じ結果になります。


ok 72 constant red 
ok
ok red . 
72
ok 

value では任意の数値に名前を付けることができます。その名前を後で実行すると、その代入値がスタックに残されます。次の例は 22 という値を foo という名前のワードに代入し、次に foo を呼び出してその代入値を演算に使用します。


ok 22 value foo
ok foo 3 + .
25
ok 

値は辞書コンパイルワード is で変更できます。たとえば、次の例を参照してください。


ok 43 value thisval
ok thisval .
43
ok 10 to thisval
ok thisval .
10
ok 

value を使用して作成したコマンドは、数値が必要な場合、@ を使用しないで済むので便利です。

ワード定義 variable は 32 ビットのメモリー領域に名前を割り当てます。この領域は必要に応じて値の保存用として使用できます。後でその名前を実行すると、領域のメモリーアドレスがスタックに残されます。一般的に、そのアドレスの読み書きには @! が使用されます。次の例を参照してください。


ok variable bar
ok 33 bar !
ok bar @ 2 + .
35
ok 

ワード定義 defer により、必要に応じて異なる機能を読み込むスロットが生成されるので、後から機能を変更できるコマンドを生成できます。次の例を参照してください。


ok hex
ok defer printit
ok ['] .d  to  printit
ok ff printit
255
ok : myprint ( n -- ) ." It is " .h
] ." in hex " ;
ok ['] myprint to printit
ok ff printit
It is ff in hex
ok 

辞書の検索

辞書」にはシステムが備えているすべての Forth コマンドが含まれています。 表 4-8 に辞書検索用のツールを示します。

表 4-8 辞書検索コマンド

コマンド  

スタックダイアグラム 

説明 

' name

( -- xt ) 

指定されたワードを辞書から検索します。実行トークンを返します。外部定義を使用します。 

['] name

( -- xt ) 

内部、外部のどちらの定義でも使用される点以外は、' と同じです。

.calls

( xt -- ) 

実行トークンが xt であるワードを呼び出すすべてのワードのリストを表示します。

$find

( addr len -- addr len false | xt n ) 

ワードを検索します。検索できなかった場合 n = 0 、検索できた場合 n = 1、それ以外の場合 n = -1 。

find

( pstr -- pstr false | xt n ) 

ワードを辞書から検索します。検索するワードは pstr です。検索できなかった場合 n = 0、検索できた場合 n = 1、それ以外の場合 n = -1 。

see thisword

( -- ) 

指定されたコマンドを逆コンパイルします。 

(see)

( xt -- ) 

実行トークンによって示されるワードを逆コンパイルします。 

sift

( pstr -- ) 

pstr によって示される文字列を含むすべての辞書エントリの名前を表示します。

sifting ccc

( -- ) 

指定された文字処理を含むすべての辞書エントリの名前を表示します。ccc 内には空白文字は含まれません。

words

( -- )  

辞書内のすべての表示可能なワードを表示します。 

see thisword の形式で使用した場合、see は指定されたコマンドを逆コンパイルします (つまり、thisword を作成するための定義を表示します)。メモリースペースを節減するために内部の名前が PROM のシンボルテーブルから省略されていることがあるため、逆コンパイル結果の定義はときとして不明確なものになる場合があります。

次の画面は sifting の使用例です。


ok sifting input 
input-device input restore-input line-input input-line input-file
ok 

words は、辞書内のすべてのワード (コマンド) 名を最新の定義から先に表示します。

データを辞書へコンパイルする

表 4-9 に、データを辞書へコンパイルするためのコマンドを示します。

表 4-9 辞書コンパイルコマンド

コマンド 

スタックダイアグラム 

説明 

,

( n -- ) 

数値を辞書に入れます。 

c,

( byte -- ) 

1 バイトを辞書に入れます。 

w,

( word -- ) 

16 ビット数値を辞書に入れます。 

l,

( quad -- ) 

32 ビット数値を辞書に入れます。 

[

( -- ) 

解釈を開始します。 

]

( -- ) 

解釈を終了し、コンパイルを再開します。 

allot

( n -- ) 

辞書に n バイトを割り当てます。

>body

( xt -- a-addr ) 

実行トークンからデータフィールドアドレスを見つけます。 

body>

( a-addr -- xt ) 

データフィールドアドレスから実行トークンを見つけます。 

compile

( -- ) 

次のワードを実行時にコンパイルします。 

[compile] name

( -- ) 

次の (すぐ次の) ワードをコンパイルします。 

forget namep

( -- ) 

指定されたワードとそれ以降の全ワードを辞書から削除します。 

here

( -- addr ) 

辞書の先頭アドレス。 

immediate

( -- ) 

最後の定義を即値としてマークします。 

to name

( n -- ) 

defer ワードまたは value に新しい処理を実装します。

literal

( n -- ) 

数値をコンパイルします。 

origin 

( -- addr ) 

Forth システムの開始アドレスを返します。 

patch new-word old-word word-to-patch

( -- ) 

old-wordword-to-patchnew-word に置き換えます。

(patch

( new-n old-n xt -- ) 

old-nxt によって示されるワードの new-n に置き換えます。

recursive 

( -- ) 

辞書内のコンパイル中のコロン定義の名前を表示可能にし、したがって、そのワードの名前をそれ自身の定義内で再帰的に使用可能にします。 

state

( -- addr ) 

コンパイル状態のゼロ以外の変数。 

数値の表示

表 4-10 にスタック値表示用の基本コマンドを示します。

表 4-10 基本数値表示

コマンド 

スタックダイアグラム 

説明 

.

( n -- ) 

数値を現在の基数で表示します。 

.r

( n size -- ) 

数値を固定幅フィールドで表示します。 

.s

( -- ) 

データスタックの内容を表示します。 

showstack

( ??? -- ??? ) 

ok プロンプトの前で自動的に .s を実行します。

noshowstack

( ??? -- ??? ) 

各 ok プロンプトの前でのスタック表示をオフにします。 

u.

( u -- ) 

符号なし数値を表示します。 

u.r

( u size -- ) 

数値を固定幅フィールドで表示します。 

.s コマンドはスタックの内容全体をそのまま表示します。このコマンドはいつでもデバッグ目的に使用して安全です。(これは、showstack が自動的に実行する機能です。)

基数の変更

表 4-11 のコマンドを使用して、現在使用している数値の基数を変更できます。

表 4-11 基数の変更

コマンド  

スタックダイアグラム 

説明 

.d

( n -- ) 

基数を変更しないで n を 10 進で表示します。

.h

( n -- ) 

基数を変更しないで n を 16 進で表示します。

base

( -- addr ) 

基数を格納している変数。 

decimal

( -- ) 

基数を 10 進に設定します。 

d# number

( -- n ) 

number を 10 進に変換します。基数は変わりません。

hex

( -- ) 

基数を 16 進に設定します。 

h# number

( -- n ) 

number を 16 進に変換します。基数は変更されません。

octal

( -- ) 

基数を 8 進に設定します。 

o# number

( -- n ) 

number を 8 進に変換します。基数は変更されません。

d#h#、o# の各コマンドは、現在の基数を明示的に変更しないで、特定の数値を別の基数で入力するときに便利です。


ok decimal       (基数を 10 進に変更)
ok 4 h# ff 17 2
4 255 17 2 ok 

.d および .h コマンドの機能は、現在の基数設定にかかわりなく、値をそれぞれ 10 進または 16 進で表示する点を除いて、「.」と同じです。次の例を参照してください。


ok hex
ok ff .  ff .d
ff 255 

テキスト入出力の制御

この節ではテキストの入出力用コマンドについて説明します。これらのコマンドは文字列や文字配列を制御し、ユーザーからのコメント入力およびキーボードの走査制御を可能にします。

表 4-12 にテキスト入力制御用のコマンドを示します。

表 4-12 テキスト入力制御

コマンド  

スタックダイアグラム 

説明 

( ccc )

( -- ) 

コメントを作成します。習慣上スタックダイアグラム用に使用されます。 

¥ rest-of-line

( -- ) 

行の残りの部分をコメントとして扱います。 

ascii ccc

( -- char ) 

次のワードの最初の ASCII 文字の数値を取り出します。 

expect

( addr +n -- ) 

割り当てられた入力デバイスのキーボードから編集結果の 1 行を受け取り、addr に格納します。

key

( -- char ) 

割り当てられた入力デバイスのキーボードから 1 文字を読みます。 

key?

( -- flag ) 

入力デバイスのキーボードでキーが押された場合 true。 

span

( -- waddr ) 

expect で読み出された文字数を格納する変数。

word

( char -- pstr ) 

入力文字列から char で区切られる文字列を集め、メモリー位置 pstr に入れます。

Forth コードのコメントは、コードの機能を記述するために、(一般的にテキストファイル内の) Forth ソースコードに使用します。( (左側括弧) がコメントを開始する Forth ワードです。) (右側括弧) の前までの文字はすべて、Forth インタプリタが無視します。スタックダイアグラムは ( を使用するコメントとして取り扱われます。


注 -

( の後に空白文字を入れることを忘れないでください。それによって、( は Forth ワードとして認識されます。


¥ (バックスラッシュ) はテキスト行末でコメントが終わりになることを示します。

key はキーが押されるまで待ち、押されると、そのキーの ASCII 値をスタックに返します。

asciiascii x の形式で使用され、文字 x の数字コードをスタックに返します。

key? はキーボードを走査して、ユーザーが新たになんらかのキーを押したかどうかを調べ、フラグをスタックに返します。つまり、キーが押されていた場合は true を、押されていない場合は false を返します。フラグの使い方については、「条件フラグ」の説明を参照してください。

表 4-13 に汎用のテキスト表示用コマンドを示します。

表 4-13 テキスト出力表示

コマンド 

スタックダイアグラム 

説明 

." ccc"

( -- ) 

後の表示に備えて、文字列をコンパイルします。 

(cr

( -- ) 

出力カーソルを現在行の先頭に戻します。 

cr

( -- ) 

ディスプレイ上の行を終了し、次の行に進みます。 

emit

( char -- ) 

現在位置の文字を表示します。 

exit?

( -- flag ) 

スクロール制御プロンプト More [<space>,<cr>,q] ?

を有効にします。リターンフラグは、ユーザーが出力を終了する場合 true です。

space

( -- ) 

空白文字を表示します。 

spaces

( +n -- )  

+n 個の空白文字を表示します。

type

( addr +n -- ) 

addr から始まる +n 個の文字を表示します。

cr はキャリッジリターン文字を出力に送ります。次の例を参照してください。


ok 3 . 44 . cr 5 .
3 44
5
ok 

emit は ASCII 値がスタックにある英字を表示します。


ok ascii a 
61 ok 42
61 42 ok emit emit
Ba
ok 

表 4-14 にテキスト文字列操作用のコマンドを示します。

表 4-14 テキスト文字列操作

コマンド  

スタックダイアグラム 

説明 

", 

( addr len -- ) 

addr から始まり、長さが len のバイトの配列をパックされた文字列としてコンパイルし、辞書の先頭に入れます。

" ccc"

( -- addr len ) 

翻訳結果またはコンパイル結果の入力ストリーム文字列をまとめます。文字列内に "(00,ff...) を使用して任意のバイト値を含めることができます。

.( ccc)

( -- )  

文字列を即時に表示します。 

-trailing

( addr +n1 -- addr +n2 ) 

後続空白文字を削除します。 

bl

( -- char ) 

空白文字の ASCII コード。10 進の 32。 

count

( pstr -- addr +n ) 

パックされている文字列をアンパックします。 

lcc

( char -- lowercase-char ) 

文字を小文字に変換します。 

left-parse-string

( addr len char -- addrR lenR addrL lenL ) 

文字列を char で分割します (char は捨てられます)。

pack

( addr len pstr -- pstr ) 

addr len からパックされた文字列を作り、pstr に入れます。

"p" ccc

( -- pstr ) 

入力ストリームから文字列をまとめ、パックされた文字列として格納します。 

upc

( char -- uppercase-char ) 

文字を大文字に変換します。 

一部の文字列操作コマンドは、アドレス (それらの文字があるメモリー内の位置) と長さ (文字列の文字数) を指定します。その他のコマンドは、パックされた文字列、または長さを表すバイトを格納するメモリー位置である pstr とその後の一連の文字を使用します。コマンドのスタックダイアグラムは、どの形式が使用されるかを示します。たとえば、count はパックされた文字列を addr-len (アドレスと長さの組み合わせ) 文字列に変換します。

コマンド ."." string" の形式で使用します。このコマンドは必要なときにテキストを出力します。" (二重引用符) はテキスト文字列の終わりを示します。次の例を参照してください。


ok  : testing 34 .  ." This is a test"  55 . ;
ok
ok testing
34 This is a test55
ok 

入出力先の変更

通常、システムはすべてのユーザー入力にキーボードを、また大部分の表示出力にディスプレイ画面付きのフレームバッファーをそれぞれ使用します。(サーバーシステムはシステムのシリアルポートに接続された ASCII 端末を使用できます。システム本体への端末の接続についての詳細は、システムのインストールマニュアルを参照してください。) 入力先、出力先、それらの両方をシステムのいずれかのシリアルポートに変更できます。これは、たとえばフレームバッファーのデバッグ時に便利です。

表 4-15 に入出力先変更用のコマンドを示します。

表 4-15 入出力先の変更用コマンド

コマンド  

スタックダイアグラム 

説明 

input

( device -- ) 

入力用のデバイス (keyboard または device-specifier) を選択します。

io

( device -- ) 

入出力用のデバイスを選択します。 

output

( device -- ) 

出力用のデバイス (screen または device-specifier) を選択します。

input および output コマンドは、それぞれ、現在の入力および出力用デバイスを一時的に変更します。変更はコマンドの入力時に行われます。システムをリセットする必要はありません。システムリセットまたは電源の再投入を行うと、入出力デバイスは NVRAM システム変数 input-deviceoutput-device に指定されているデフォルト設定に戻ります。これらの変数は、必要に応じて変更できます (デフォルトの変更についての詳細は、第 3 章「システム変数の設定」を参照してください)。

input の前には、keyboardttyattyb または device-specifier テキスト文字列のうちのどれか 1 つを入れます。たとえば、入力が現在キーボードから受け入れられていて、入力がシリアルポート ttya に接続されている端末から受け入れられるように変更する場合、次のように入力します。


ok ttya input
ok 

この時点で、キーボードは (Stop-A 以外は) 機能しなくなりますが、ttya に接続されている端末から入力されるテキストはすべて入力として処理されるようになります。すべてのコマンドが通常どおりに実行されます。

キーボードを再び入力デバイスとして使用するには、端末のキーボードを使用して次のように入力します。


ok keyboard input 
ok

同様に、output の前にも screenttya、または ttyb のどれか 1 つを入れます。たとえば、通常のディスプレイ画面でなく、ttya に出力を送る場合は、次のように入力します。


ok ttya output 

通常のディスプレイ画面は応答の ok プロンプトを表示せずok プロンプトも以降のすべての出力も ttya に接続されている端末に表示されます。

io も、入出力の両方を指定した場所に変更する点以外、同じ方法で使用されます。

一般的に、inputoutputio には device-specifier を指定する必要があります。device-specifier はデバイスパス名、デバイスの別名のどちらでもかまいません。次の 2 つの例に示すように、デバイスは、二重引用符 (") を使用して Forth の文字列として次のように指定する必要があります。


ok " /sbus/cgsix" output

または、次のように指定します。


ok " screen" output

上記の 2 つの例では 、ttyascreenkeyboard は Forth のワードであり、いずれも、それぞれの対応のデバイス別名文字列をスタックに入れます。

コマンド行エディタ

OpenBoot では、ユーザーインタフェース用として (一般的なテキストエディタである EMACS のような) 使用するコマンド行エディタ、一部のオプション拡張、オプションの履歴用機能を指定しています。これらの強力なツールを使用して、前のコマンドを入力し直さないで再び実行して、現在のコマンド行を編集して入力エラーを修正し、前のコマンドを呼び出すことができます。

表 4-16 に、ok プロンプト時に使用できる行編集用のコマンドを示します。

表 4-16 コマンド行エディタ用必須キー操作コマンド

操作キー 

説明 

Delete 

1 つ前の文字を消去します。 

Backspace 

1 つ前の文字を消去します。 

Control-U 

現在の行を消去します。 

Return (Enter) 

現在の行の編集を終了し、表示されている 1 行全部をインタプリタに渡します。 

OpenBoot 標準でも、これらの機能の 3 つの拡張グループを記述しています。 表 4-17 に、コマンド行編集用の拡張グループを示します。

表 4-17 コマンド行エディタ用オプションキー操作コマンド

操作キー 

説明 

Control-B 

1 文字位置戻ります。 

Escape B 

1 語後戻ります。 

Control-F 

1 文字位置進みます。 

Escape F 

1 語進みます。 

Control-A 

行の始めまで戻ります。 

Control-E 

行の終わりに進みます。 

Delete 

前の 1 文字を消去します。 

Backspace 

前の 1 文字を消去します。 

Control-H 

前の 1 文字を消去します。 

Escape H 

語の初めからカーソルの直前まで消去し、消去した文字を保存バッファーに格納します。 

Control-W 

語の初めからカーソルの直前まで消去し、消去した文字を保存バッファーに格納します。 

Control-D 

カーソル位置の文字を消去します。 

Escape D 

カーソル位置から語の終りまで消去し、消去した文字を保存バッファーに格納します。 

Control-K 

カーソル位置から行の終りまで消去し、消去した文字を保存バッファーに格納します。 

Control-U 

1 行を全部消去し、消去した文字を保存バッファーに格納します。 

Control-R 

1 行を表示しなおします。 

Control-Q 

次の文字の前に引用符を付けます (制御文字を挿入できます)。 

Control-Y 

保存バッファーの内容をカーソル位置の前に挿入します。 

コマンド行履歴の拡張機能として、前に入力したコマンドを EMACS のようなコマンド履歴バッファーに保存できます。このバッファーは 8 エントリ以上入れることができます。保存したコマンドは、バッファー内を前後に移動することにより、再び呼び出すことができます。呼び出したコマンドは、編集したり、(Return キーを押して) 再びインタプリタに渡すことができます。表 4-18 にコマンド行履歴拡張用のキーを示します。

表 4-18 コマンド行履歴用オプションキー操作コマンド

操作キー 

説明 

Control-P 

コマンド履歴バッファー内の 1 行前のコマンド行を表示します。 

Control-N 

コマンド履歴バッファー内の次のコマンド行を表示します。 

Control-L 

コマンド履歴バッファー全てを表示します。 

コマンド名補完機能では、ワードのすでに入力した部分に基づいて辞書から 1 つまたはそれ以上の一致するワードを検索して、長い Forth のワード名を補完します。ワードの一部を入力した後にコマンド補完キー操作として Control-Space を押すと、システムは次のように応答します。

表 4-19 にコマンド補完拡張用のキーを示します。

表 4-19 コマンド補完用オプションキー操作コマンド

操作キー 

説明 

Control-Space 

現在のワードの名前を補完します。 

Control-? 

現在のワードのすべての一致候補を表示します。 

Control-/ 

現在のワードのすべての一致候補を表示します。 

条件フラグ

Forth の条件付き制御コマンドはフラグを使用して真/偽の値を示します。フラグは、テスト基準に基づいて、いくつかの方法で生成できます。生成できたら、ワード "." でスタックから表示したり、条件付き制御コマンドの入力として使用できます。条件付き制御コマンドは、フラグが真 (true) の場合と偽 (false) の場合にそれぞれ異なる応答を表示します。

表示値が 0 の場合は、フラグの値が false であることを示します。-1 またはその他のゼロ以外の任意の数値は、フラグが true であることを示します。(16 進では、値 -1ffffffff として表示されます。)

表 4-20 に、比較テストを実行し、true または false フラグの結果をスタックに残すコマンドを示します。

表 4-20 比較コマンド

コマンド  

スタックダイアグラム 

説明 

<

( n1 n2 -- flag ) 

n1 < n2 の場合 true。

<=

( n1 n2 -- flag ) 

n1 <= n2 の場合 true。

<>

( n1 n2 -- flag ) 

n1 <> n2 の場合 true。

=

( n1 n2 -- flag ) 

n1 = n2 の場合 true。

>

( n1 n2 -- flag ) 

n1 > n2 の場合 true。

>=

( n1 n2 -- flag ) 

n1 >= n2 の場合 true。

0<

( n -- flag ) 

n < 0 の場合 true。

0<=

( n -- flag ) 

n <= 0 の場合 true。

0<>

( n -- flag ) 

n <> 0 の場合 true。

0=

( n -- flag ) 

n = 0 (さらにフラグを反転します)。

0>

( n -- flag ) 

n > 0 の場合 true。

0>=

( n -- flag )  

n >= 0 の場合 true。

between

( n min max -- flag ) 

min <= n <= max の場合 true。

false

( -- 0 ) 

FALSE (偽) の値 0。

true

( -- -1 ) 

TRUE (真) の値 -1。

u<

( u1 u2 -- flag ) 

u1 < u2 の場合 true。u1、u2 とも符号なし。

u<=

( u1 u2 -- flag ) 

u1 <= u2 の場合 true。u1、u2 とも符号なし。

u>

( u1 u2 -- flag ) 

u1 > u2 の場合 true。u1、u2 とも符号なし。

u>=

( u1 u2 -- flag ) 

u1 >= u2 の場合 true。u1、u2 とも符号なし。

within

( n min max -- flag ) 

min <= n < max の場合 true。

> はスタックから 2 つの数値を取り出し、最初の数値が 2 番目の数値より大きかった場合は true (-1) をスタックに返し、そうでなかった場合は false (0) を返します。次に例を示します。


ok 3 6 > .
0                (3 は 6 より大きくない)  
ok 

0= はスタックから 1 項目を取り出し、その項目が 0 であった場合は true を返し、そうでなかった場合は false を返します。このワードはどちらのフラグもその反対の値に反転します。

制御コマンド

以降の各項では、Forth プログラム内の実行フローの制御用のワードについて説明します。

if-else-then 構造

ifthenelse の各コマンドは組み合わされて単純な制御構造を作ります。

表 4-21 に条件付き実行フロー制御用のコマンドを示します。

表 4-21 if..else..then コマンド

コマンド  

スタックダイアグラム 

説明 

if

( flag -- ) 

flagtrue の場合、このコマンドの後のコードを実行します。

else

( -- ) 

iffalse の場合、このコマンドの後のコードを実行します。

then

( -- ) 

if...else...then を終了します。

これらのコマンドの書式は次のとおりです。


flag if
    (true の場合これを実行)
else
    (false の場合これを実行)
then
    (通常どおりに実行を継続) 

または


flag if
    (true の場合これを実行)
then
    (通常どおりに実行を継続)

if コマンドはスタックからフラグを 1 つ「消費」します。そのフラグが true (ゼロ以外) であれば、if の後のコマンドが実行されます。true でなければ、(存在する場合) else の後のコマンドが実行されます。


ok : testit  ( n -- )  
] 5 >  if  ." good enough "  
] else  ." too small "  
] then  
] ." Done. "  ; 
ok
ok 8 testit
good enough Done. 
ok 2 testit 
too small Done. 
ok 


注 -

] プロンプトは、それが現れる間は、新しいコロン定義の作成の途中であることをユーザーに示します。このプロンプトはセミコロンを入力して定義を終了すると ok に戻ります。


case

高水準の case コマンドであり、複数の候補のなかから代替実行フローを選択するために用意されています。このコマンドの方が、深く入れ子になった if...then コマンドよりも読みやすいという利点があります。

表 4-22 に条件付き case コマンドを示します。

表 4-22 case 文コマンド

コマンド  

スタックダイアグラム 

説明 

case

( selector -- selector )  

case...endcase 条件付き構造を開始します。

endcase

( selector | {empty} -- ) 

case...endcase 条件付き構造を終了します。

endof

( -- ) 

条件付き構造内の of...endof 句を終了します。

of

( selector test-value -- selector | {empty} ) 

case 条件付き構造内の of...endof 句を開始します。

case コマンドの使用例を示します。


ok : testit  ( testvalue -- )
]  case  0  of  ." It was zero "  endof 
]    1  of  ." It was one "  endof 
]    ff of  ." Correct "  endof 
]    -2 of  ." It was minus-two "  endof 
]    ( default )  ." It was this value: "  dup . 
]  endcase   ." All done."  ; 
ok
ok 1 testit
It was one All done.
ok ff testit
Correct All done.
ok 4 testit
It was this value: 4 All done.
ok 


注 -

(省略可能な) default 句はまだスタックにあるテスト値を使用できますが、その値を削除してはなりません ("." でなく "dup ."を使用してください)。of 句が正常に実行されれば、テスト値はスタックから自動的に削除されます。


begin ループ

begin ループは、特定の条件が満たされるまで、同じコマンドの実行を繰り返します。そのようなループのことを条件付きループといいます。

表 4-23 に条件付きループの実行制御用のコマンドを示します。

表 4-23 begin (条件付き) ループコマンド

コマンド  

スタックダイアグラム 

説明 

again

( -- ) 

begin...again 無限ループを終了します。

begin

( -- ) 

begin...while...repeatbegin...until または begin...again ループを開始します。

repeat

( -- ) 

begin...while...repeat ループを終了します。

until

( flag -- ) 

flag が true である間、begin...until ループの実行を続けます。

while

( flag -- ) 

flag が true の間、begin...while...repeat ループの実行を続けます。

次に 2 つの一般的な形式を示します。


begin    any commands...flag until 

および


begin    any commands...flagwhile
       more commands repeat

上記の両方の場合とも、所定のフラグ値によってループが終了させられるまで、ループ内のコマンドが繰り返し実行されます。ループが終了すると、通常、実行はループを閉じているワード (until または repeat) の後のコマンドに継続されます。

begin...until の場合は、until がスタックの一番上からフラグを削除してそれを調べます。フラグが false の場合は、実行は begin のすぐ後に引き継がれて、ループが繰り返されます。フラグの true の場合は、実行はループから抜け出ます。

begin...while...repeat の場合は、while がスタックの一番上からフラグを削除して調べます。フラグが true の場合は、while のすぐ後のコマンドが実行されてループが繰り返されます。repeat コマンドは制御を自動的に begin に戻してループを継続させます。while が現れたときにフラグが false であった場合は、実行はただちにループから抜け出し、制御がループを閉じている repeat の後の最初のコマンドに移ります。

これらのループのいずれについても、「true ならば通り過ぎる」と覚えてください。

次に簡単な例を示します。


ok begin 4000 c@ .  key? until (任意のキーが押されるまで繰り返す)
43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43
ok 

この例では、ループはまずメモリー位置 4000 から 1 バイトを取り出して表示します。次に、key? コマンドが呼び出され、ユーザーがそれまでにいずれかのキーを押していれば true をスタックに残し、そうでない場合は false を残します。このフラグは until によって「消費」され、その値が false であった場合は、ループが繰り返されます。キーを押せば、次に呼び出されたとき、key?true を返し、したがってループは終了します。

Forth の多くのバージョンとは異なり、ユーザーインタフェースの場合は、ループや条件付き制御構造を対話的に使用できます。つまり、最初に定義を作成する必要がありません。

do ループ

do ループ (カウント付きループとも呼ばれます) は、ループの繰り返し回数があらかじめ計算できるときに使用します。do ループは、通常、指定した終了値に達する直前に終了します。

表 4-24 に カウント付きループの実行制御用コマンドを示します。

表 4-24 do (カウント付き) ループコマンド

コマンド 

スタックダイアグラム 

説明 

+loop

( n -- ) 

do...+loop 構造を終了します。ループインデックスに n を加算し、do に戻ります (n < 0 の場合は、インデックスは start から end まで使用されます)。

?do

( end start -- ) 

?do...loop の 0 回またはそれ以上の実行を開始します。インデックスは start から end-1 まで使用されます。end = start の場合はループは実行されません。

?leave

( flag -- ) 

flag がゼロ以外の場合、実行を do...loop から抜けます。

do

( end start -- ) 

do...loop を開始します。インデックスは start から end まで使用されます。

例: 10 0 do i . loop ( 0 1 2...d e f と出力します)

i

( -- n ) 

ループインデックスをスタックに残します。 

j

( -- n ) 

1 つ外側のループのループインデックスをスタックに残します。 

leave

( -- ) 

実行を do...loop から抜けます。

loop

( -- ) 

do...loop を終了します。

次の画面で、ループの使用方法をいくつか示します。


ok 10 5 do  i .  loop 
5 6 7 8 9 a b c d e f
ok
ok 2000 1000 do i .  i c@ . cr   i c@ ff = if leave then  4 +loop 
1000 23
1004 0
1008 fe
100c 0
1010 78
1014 ff
ok : scan ( byte -- ) 
]    6000 5000     (5000 〜 6000 のメモリー領域を走査して指定のバイト値に一致しないバイトを調べる)
]    do dup i c@ <> (  byte error? )  
]      if i . then  ( byte ) 
]    loop 
]    drop ( the original byte was still on the stack, discard it ) 
]  ; 
ok 55 scan 
5005 5224 5f99 
ok 6000 5000 do i i c! loop     (メモリー領域にステップパターンを埋め込む)
ok       
ok 500 value testloc 
ok : test16 ( -- ) 1.0000 0 ( do 0-ffff )     (指定位置に異なる 16 ビット値を書き込む)
]     do i testloc w! testloc w@ i <> ( error? )      (さらに位置をチェック)
]       if ." Error - wrote " i . ." read " testloc w@ . cr 
]        leave ( exit after first error found )      (この行は省略可能)
]       then 
]     loop 
]  ; 
ok test16 
ok 6000 to testloc 
ok test16 
Error - wrote 200 read 300 
ok 

その他の制御コマンド

表 4-25 に、前記以外のプログラム実行制御用のコマンドについて説明します。

表 4-25 プログラム実行制御コマンド

コマンド  

スタックダイアグラム 

説明 

abort

( -- ) 

現在の実行を終了させ、キーボードコマンドを解釈します。 

abort"ccc"

( abort? -- ) 

abort? が true の場合は、実行を終了させてメッセージを表示します。

eval

( addr len -- ) 

配列から Forth のソースを解釈します。 

execute

( xt -- ) 

実行トークンがスタックにあるワードを実行します。 

exit

( -- ) 

現在のワードから復帰します。(カウント付きループでは使用できません。) 

quit

( -- ) 

スタック内容をまったく変えない点を除いて、abort と同じです。

abort はプログラムの実行を即時に終了させ、制御をキーボードに返します。abort" は 2 点を除いて abort と同じです。第 1 点は、フラグが true の場合にスタックからフラグを削除し、その後は何もしないで強制終了させることです。もう 1 点は、強制終了が行われたとき、なんらかのメッセージを表示することです。

eval は (アドレスと長さにより指定された) 文字列をスタックから取り出します。次に、キーボードから入力される場合と同様に、その文字列の文字が解釈されます。Forth のテキストファイルをメモリーに読み込んでいる (第 5 章「プログラムの読み込みと実行」を参照) 場合は、eval を使用してそのファイル内の定義をコンパイルできます。