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

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

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

OpenBoot に含まれる Forth のバージョンは、ANS Forth に準拠しています。「付録 I 「Forth ワードリファレンス」」に全コマンドのリストを載せてあります。


注 -

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


Forth コマンド

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


@
dump
.
0<
+
probe-scsi

probe-scsi コマンドとして認識されるためには、Forth ワードはそれぞれの間を 1 つまたはそれ以上の空白文字で分離する必要があります。他の一部のプログラミング言語で通常「句読文字」として取り扱われる文字は、Forth ワード間の区切りには使用されません。実際には、それらの多くの「句読文字」は Forth ワードそのものなのです。

どのコマンド行の終わりで Return キーを押しても、そこまで入力したコマンドが実行されます。(この章に示すすべての例で、行の終わりでは Return キーが押されるものとしています。)

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


ok testa testb testc 
ok 

次の 3 行と同じです。


ok testa 
ok testb 
ok testc 
ok 

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

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


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

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

データ型

表 4-1に示す用語は Forth が使用するデータ型です。

表 4-1 Forth データ型の定義

表記 

説明 

byte

8 ビット値。 

cell

実装によって定義される固定サイズのセルであり、アドレス単位と対応のビット数で指定されます。データスタック要素、復帰スタック要素、アドレス、実行トークン、フラグ、整数は 1 セル幅です。 

OpenBoot システムでは、セルは最低 32 ビットからなり、十分に仮想アドレスを格納できます。セルサイズは実装によって異なることがあります。「32 ビット」実装のセルサイズは 4 であり、「64 ビット」実装のセルサイズは 8 です。 

doublet

16 ビット値。 

octlet

64 ビット値。64 ビット実装にかぎり定義されます。 

quadlet

32 ビット値。 

数値の用法

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

特に指定がないかぎり、OpenBoot は 1 セルサイズのデータ項目の整数演算を実行して、1 セルサイズの結果を生成します。

OpenBoot の実装ではデフォルトで基数 16 (16 進数) を使用するよう奨励していますが、必ずそうしなければならないわけではありません。したがって、正しく演算されるためにコードが特定の基数に依存する場合は、そのような基数を設定する必要があります。decimalhex といったコマンドを使用して変更できます。これらのコマンドは、以降の数値の入出力をそれぞれ 10、16 を基数として行わせます。

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


ok decimal 
ok 

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


ok hex 
ok 

現在使用されている基数を知る方法を次に示します。


ok 10 .d
16
ok 

上記の画面に表示されている 16 は、16 進で演算が行われることを示しています。10 が表示される場合は、10 を基数としていることを意味します。.d は、現在の基数とは無関係に 10 を基数として表示します。

スタック

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) を削除し、それを表示します。

スタックの内容に影響しないワード (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

利用者定義の作成

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

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

コマンド 

スタックダイアグラム 

説明 

: 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 

これらの定義はシステムをリセットすると消去されます。よく使う定義を保存するには、それらをスクリプトにする、つまりテキストファイルにして、ホストシステムにそれらの定義を保存します。このテキストファイルは、以降、必要に応じて読み込みできます。(ファイルの読み込みについての詳細は、第 5 章「プログラムの読み込みと実行」を参照してください。)

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


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

複数行の定義に ] プロンプトを使用するのは、サン・マイクロシステムズ社の実装の特徴です。

演算機能の使用方法

単精度整数演算

表 4-5に示すコマンドは、単精度整数演算を行います。

表 4-5 単精度演算機能

コマンド 

スタックダイアグラム 

説明 

+

( nu1 nu2 -- sum ) 

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

-

( nu1 nu2 -- diff ) 

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

*

( nu1 nu2 -- prod ) 

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

*/

( n1 n2 n3 -- quot ) 

nu1 * nu2 / n3 を計算します。入力、出力、中間値はすべて 1 つのセルに入ります。

/

( n1 n2 -- quot ) 

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

1+

( nu1 -- nu2 ) 

1 を足します。 

1-

( nu1 -- nu2 ) 

1 を引きます。 

2+

( nu1 -- nu2 ) 

2 を足します。 

2-

( nu1 -- nu2 )  

2 を引きます。 

abs

( n -- u ) 

絶対値。 

bounds

( start len -- len+start start ) 

do または ?do ループ用に startlenendstart に変換します。

even

( n -- n | n+1 ) 

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

max

( n1 n2 -- n3 ) 

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

min

( n1 n2 -- n3 ) 

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

mod

( n1 n2 -- rem ) 

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

*/mod

( n1 n2 n3 -- rem quot ) 

n1 * n2 / n3 の剰余と商。

/mod

( n1 n2 -- rem quot ) 

n1 / n2 の剰余と商。

negate

( n1 -- n2 ) 

n1 の符号を変更します。

u*

(u1 u2 -- uprod ) 

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

u/mod

( u1 u2 -- urem uquot ) 

符号なし 1 セル数値を符号なし 1 セル数値で割り、 1 セルの剰余と商を生じます。 

<<

( x1 u -- x2 ) 

lshift の同義語。

>>

( x1 u -- x2 ) 

rshift の同義語。

2*

( x1 -- x2 ) 

2 を掛けます。 

2/

( x1 -- x2 ) 

2 で割ります。 

>>a

( x1 u -- x2 ) 

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

and

( x1 x2 -- x3 ) 

ビット単位の論理積。 

invert

( x1 -- x2 ) 

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

lshift

( x1 u -- x2 ) 

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

not

( x1 -- x2 ) 

invert の同義語。

or

( x1 x2 -- x3 ) 

ビット単位の論理和。 

rshift

( x1 u -- x2 ) 

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

u2/

( x1 -- x2 ) 

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

xor

( x1 x2 -- x3 ) 

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

倍精度数演算

表 4-6に示すコマンドは倍精度数の演算を行います。

表 4-6 倍精度数演算機能

コマンド 

スタックダイアグラム 

説明 

d+

( d1 d2 -- d.sum ) 

d1 を d2 に足し、倍精度数 d.sum を生じます。 

d-

( d1 d2 --d.diff ) 

d1 から d2 を引き、倍精度数 d.diff を生じます。 

fm/mod

( d n -- rem quot ) 

d を n で割ります。

m*

( n1 n2 -- d ) 

符号付き乗算を行い、倍精度数の積を生じます。 

s>d

( n1 -- d1 ) 

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

sm/rem

( d n -- rem quot ) 

dn で割ります。対称除算。

um*

( u1 u2 -- ud ) 

符号なし乗算を行い、符号なし倍精度数の積を生じます。 

um/mod

( ud u -- urem uprod ) 

udu で割ります。

データ型変換

表 4-7に示すコマンドはデータ型の変換を行います。

表 4-7 32 ビットデータ型変換機能

コマンド 

スタックダイアグラム 

説明 

bljoin

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

4 バイトを結合して quadlet (32 ビット) を作ります。 

bwjoin

( b.low b.hi -- word ) 

2 バイトを結合して doublet (16 ビット) を作ります。 

lbflip

( quad1 -- quad2 ) 

quadlet 内の 4 バイトを逆に並べ替えます。 

lbsplit

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

quadlet を 4 バイトに分割します。 

lwflip

( quad1 -- quad2 ) 

quadlet 内の 2 つの doublet をスワップします。 

lwsplit

( quad -- w.low w.hi ) 

quadlet を 2 つの doublet に分割します。 

wbflip

( word1 -- word2 ) 

doublet 内の 2 バイトをスワップします。 

wbsplit

( word -- b.low b.hi ) 

doublet を 2 バイトに分割します。 

wljoin

( w.low w.hi -- quad ) 

2 つの doublet を結合して quadlet を作ります。 

表 4-8に示すデータ型変換用コマンドは 64 ビットの OpenBoot 実装専用です。

表 4-8 64 ビットデータ型変換機能

コマンド 

スタックダイアグラム 

説明 

bxjoin

( b.lo b.2 b.3 b.4 b.5 b.6 b.7 b.hi -- o ) 

8 バイトを結合して octlet を作ります。 

lxjoin

( quad.lo quad.hi -- o ) 

2 つの quadlet を結合して octlet を作ります。 

wxjoin

( w.lo w.2 w.3 w.hi -- o ) 

4 つの doublet を結合して octlet を作ります。 

xbflip

( oct1 -- oct2 ) 

octlet 内の 8 バイトを逆に並べ替えます。 

xbsplit

( o -- b.lo b.2 b.3 b.4 b.5 b.6 b.7 b.hi ) 

octlet を 8 バイトに分割します。 

xlflip

( oct1 -- oct2 ) 

octlet 内の 2 つの quadlet をスワップします。各 quadlet 内の 4 バイトは逆に並べ替えられません。 

xlsplit

( o -- quad.lo quad.hi ) 

octlet を 2 つの quadlet に分割します。 

xwflip

( oct1 -- oct2 ) 

octlet 内の 4 つの doublet を逆に並べ替えます。各 doublet 内の 2 バイトは並べ替えられません。 

xwsplit

( o -- w.lo w.2 w.3 w.hi ) 

octlet を 4 つの doublet に分割します。 

アドレス演算

表 4-9に示すコマンドはアドレス演算を行います。

表 4-9 アドレス演算機能

コマンド 

スタックダイアグラム 

説明 

aligned

( n1 -- n1 | a-addr) 

必要な場合、 n1 大きくして可変境界アドレスを生じます。

/c

( -- n ) 

バイトのアドレス単位数 : 1。 

/c*

( nu1 -- nu2 ) 

chars の同義語。

ca+

( addr1 index -- addr2 ) 

addr1/c の値の index 倍増やします。

ca1+

( addr1 -- addr2 ) 

char+ の同義語。

cell+

( addr1 -- addr2 ) 

addr1/n の値だけ増やします。

cells

( nu1 -- nu2 ) 

nu1/n の値を掛けます。

char+

( addr1 -- addr2 ) 

addr1/c の値だけ増やします。

chars

( nu1 -- nu2 ) 

nu1/c の値を掛けます。

/l

( -- n ) 

quadlet のアドレス単位数 : 通常 4。 

/l*

( nu1 -- nu2 ) 

nu1/l の値を掛けます。

la+

( addr1 index -- addr2 ) 

addr1/l の値の index 倍増やします。

la1+

( addr1 -- addr2 ) 

addr1/l の値だけ増やします。

/n

( -- n ) 

セルのアドレス単位数。 

/n*

( nu1 -- nu2 ) 

cells の同義語。

na+

( addr1 index -- addr2 ) 

addr1/n の値 index 倍増やします。

na1+

( addr1 -- addr2 ) 

cell+ の同義語。

/w

( -- n ) 

doublet のアドレス単位数 : 通常 2。 

/w*

( nu1 -- nu2 ) 

nu1/w の値を掛けます。

wa+

( addr1 index -- addr2 ) 

addr1/w の値の index 倍増やします。

wa1+

( addr1 -- addr2 ) 

addr1/w の値だけ増やします。

表 4-10に示すアドレス演算用コマンドは 64 ビットの OpenBoot 実装専用です。

表 4-10 64 ビットアドレス演算機能

コマンド 

スタックダイアグラム 

説明 

/x

( -- n ) 

octlet のアドレス単位数 : 通常 8。 

/x*

( nu1 -- nu2 ) 

nu1 に /x の値を掛けます。

xa+

( addr1 index -- addr2 ) 

addr1 /x の値のindex 倍増やします。

xa1+

( addr1 -- addr2 ) 

addr1/x の値だけ増やします。

メモリーのアクセス

仮想メモリー

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

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

8 ビット、16 ビット、32 ビット (システムによっては 64 ビット) のさまざまな操作ができます。一般的に、c (文字) という 接頭辞は 8 ビット (1 バイト) の操作を示し、w (ワード) という接頭辞は 16 ビット (doublet) の操作を示し、l (ロングワード) という接頭辞は 32 ビット (quadlet) の操作を示します。x という接頭辞は 64 ビット (octlet) 操作を示します。

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


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

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

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

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

コマンド  

スタックダイアグラム 

説明 

!

( x a-addr -- ) 

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

+!

( nu a-addr -- ) 

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

@

( 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 から取り出します。

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!

( q qaddr -- ) 

quadlet qqaddr に格納します。

l@

( qaddr -- q ) 

quadlet qqaddr から取り出します。

lbflips

( qaddr len -- ) 

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

lwflips

( qaddr len -- ) 

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

lpeek

( qaddr -- false | quad true ) 

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

lpoke

( q qaddr -- okay? ) 

quadlet 8 を 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!

( q addr -- ) 

quadlet q を任意の境界に格納します。

unaligned-l@

( addr -- q ) 

quadlet q を任意の境界で取り出します。

unaligned-w!

( w addr -- ) 

doublet w を任意の境界に格納します。

unaligned-w@

( addr -- w ) 

doublet w を任意の境界で取り出します。

w!

( w waddr -- ) 

doublet wwaddr に格納します。

w@

( waddr -- w) 

doublet wwaddr から取り出します。

<w@

( waddr -- n ) 

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

wbflips

( waddr len -- ) 

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

wpeek

( waddr -- false | w true ) 

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

wpoke

( w waddr -- okay? ) 

doublet w の数値を waddr に格納します。アクセスが成功した場合はそのデータと true を返し、読み取りエラーが発生した場合は false を返します。

表 4-12に示すメモリーアクセス用コマンドは 64 ビットの OpenBoot 実装専用です。

表 4-12 64 ビットメモリーアクセス機能

コマンド 

スタックダイアブラム 

説明 

<l@

( qaddr -- n ) 

quadlet を qaddr から符号を拡張して取り出します。 

x@

( oaddr -- o ) 

octlet を 64 ビット 境界アドレスから取り出します。 

x!

( o oaddr -- ) 

octlet を 64 ビット 境界アドレスに格納します。 

xbflips

( oaddr len -- ) 

指定された領域の各 octlet 内の 8 バイトを逆に並べ替えます。len が /x の整数倍でない場合は、動作は不定です。

xlflips

( oaddr len -- ) 

指定された領域の各 octlet 内の 2 つの quadlet をスワップします。各 quadlet 内の 4 バイトは逆に並べ替えられません。len が /x の整数倍でない場合は、動作は不定です。

xwflips

( oaddr len -- ) 

指定された領域の各 octlet 内の 4 つの doublet を逆に並べ替えます。各 doublet 内の 2 バイトはスワップされません。len が /x の整数倍でない場合は、動作は不定です。

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 

一部の実装は、メモリーを16、32、64 の各ビット値として表示する、dump のバリエーションをサポートしています。sifting dump (「辞書の検索」を参照) を使用すれば、システムにそのようなバリエーションがあるかどうかを確認できます。

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

表 4-13にメモリーマップ操作用のコマンドを示します。

表 4-13 メモリーマップコマンド

コマンド 

スタックダイアグラム 

説明 

alloc-mem

( len -- a-addr ) 

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

free-mem

( a-addr len -- ) 

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

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

デバイスレジスタ

前項で説明の仮想メモリーアクセス用のオペレータ (コマンド) を使用してデバイスレジスタをアクセスした場合、信頼性が欠けることがあります。デバイスレジスタアクセス用には特別なオペレータ (コマンド) があります。それらのオペレータ (コマンド) の場合は、使用する前にマシンを正しく設定する必要があります。これについての詳細は、『Writing FCode 3.x Programs』を参照してください。

ワード定義の使用方法

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

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

表 4-14に新しい Forth ワードを作成するためのワード定義を示します。

ある Forth コマンドが既存のコマンドと同じ名前で作成されると、新しいコマンドが正常に作成されます。実装によっては 「new-name isn't unique」 というメッセージが表示されます。そのコマンドの以前の使用方法は、影響を受けません。そのコマンド名をそのあとに使用する場合、最新の定義を使用します。コマンド名の同じものはすべて同じ動作をするようにするには、patch を使用して修正してください。(patch(patch) の使用方法」を参照してください。)

表 4-14 ワード定義

コマンド  

スタックダイアグラム 

説明 

: name

( -- ) (E: ... -- ??? ) 

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

;

( -- ) 

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

alias new-name old-name

( -- ) (E: ... -- ??? ) 

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

buffer: name

( size -- ) (E: -- a-addr )  

指定されたデータバッファーを作成します。name は a-addr を返します。 

constant name

( x -- ) (E: -- x )  

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

2constant name

( x1 x2 -- ) (E: -- x1 x2 )  

2 つの数値の定数を作成します。  

create name

( -- ) (E: -- a-addr )  

別のコマンドにより設定される動作を行う新しいコマンドを作成します。 

$create

( name-str name-len -- ) 

name-string によって指定される名前を使用して create を実行します。

defer name

( -- ) (E: ... -- ??? )  

別の動作を行うコマンドを作成します。to で変更します。

does>

( ... -- ... a-addr ) 

(E: ... -- ??? )  

create で作成されたワードの実行時の動作を指定します。

field name

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

指定された name でフィールドオフセットポインタを作成します。 

struct

( -- 0 ) 

struct...field 定義を開始します。

value name

( x -- ) (E: -- x )  

指定された変数を作成します。to で変更します。

variable name

( -- ) (E: -- a-addr )  

指定された変数を作成します。name は a-addr を返します。 

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


ok 22 value foo
ok foo 3 + .
25
ok 

値は to で変更できます。たとえば、次の例を参照してください。


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

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

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


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-15に辞書検索用のツールを示します。これらのツールの一部は、方法またはコマンドだけを検索処理の対象とするのに対して、その他のツールは (たとえば、変数や値をはじめとする) すべての種類のワードを対象とすることに注意してください。

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

コマンド  

スタックダイアグラム 

説明 

' name

( -- xt ) 

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

['] name

( -- xt ) 

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

.calls

( xt -- ) 

実行トークンが xt を使用するすべてのコマンドのリストを表示します。

$find

( str len -- xt true | str len false ) 

str,len によって指定されるワードを探します。見つかった場合は、xt と true をスタックに残します。見つからなかった場合は、名前の文字列と false をスタックに残します。 

find

( pstr -- xt n | pstr false ) 

pstr によって指定されるワードを探します。見つかった場合は、xt と true をスタックに残します。見つからなかった場合は、名前の文字列と false をスタックに残します。(パックされた文字列を使用しないようにするため、 $find を使用するよう推奨します)。

see thisword

( -- ) 

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

(see)

( xt -- ) 

実行トークンが xt であるワードを逆コンパイルします。 

$sift

( text-addr text-len -- ) 

text-string を含むすべてのコマンド名を表示します。 

sifting text

( -- ) 

text を含むすべてのコマンド名を表示します text 内には空白文字はありません。

words

( -- )  

次に説明するように辞書内のすべてのワードを表示します。 

辞書検索ツールの動作を理解するには、その前に、ワードがどのようにして見えるようになるかを理解する必要があります。ワードを定義するときにアクティブパッケージがあった場合は、新しいワードはその有効パッケージの方法になり、そのパッケージが有効のときしか見えません。devfind-device というコマンドを使用して、有効パッケージを選択したり、変更することができます。コマンド device-end は、現在有効なパッケージの選択を解除して、有効パッケージをなくします。

ワードを定義するときにアクティブパッケージがなかった場合は、そのワードはグローバルに見ることができます。(つまり、特定のパッケージ専用ではなく、つねに使用可能です)。

辞書検索コマンドは、存在する場合、最初に有効パッケージのワードに対して検索し、次にグローバルに見えるワードに対して検索します。


注 -

Forth コマンドの onlyalso が、どのワードを見えるようにするかを制御します。


.calls を使用して、それぞれの定義に指定されたワードを使用しているすべての Forth コマンドを検索できます。.calls はスタックから実行トークンを取り出し、辞書全体を検索して、その実行トークンを使用しているすべての Forth コマンドの名前とアドレスのリストを生成します。次の例を参照してください。


ok ' input .calls
	Called from input at 1e248d8
	Called from io at 1e24ac0
	Called from install-console at 1e33598
	Called from install-console at 1e33678
ok

see は、

see thisword

の形式で使用すると、thisword のソースの「プリティプリント」リストを表示します。次の例を参照してください。


ok see see
: see 
	 [] (see) catch if 
		drop 
	then 
; 
ok

see の使用上の詳細は、「Forth 言語逆コンパイラの使用方法」を参照してください。

sifting は入力ストリームから文字列を取り出し、辞書の検索順にすべての語を調べ、次の画面に示すように、指定された文字列を含むすべてのコマンド名を見つけます。


ok sifting input
		In vocabulary options 
(1e333f8) input-device 
		In vocabulary forth 
(1e2476c) input							(1e0a9b4) set-input							(1e0a978) restore-input 
(1e0a940) save-input						(1e0a7f0) more-input?						(1e086cc) input-file 
ok

words は辞書内のすべての見えるワード名を、最も新しい定義から先に表示します。ノードが現在 (たとえば dev で) 選択されている場合は、words によって生成されるリストはその選択されているノードのワードだけに限定されます。

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

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

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

コマンド 

スタックダイアグラム 

説明 

,

( n -- ) 

数値を辞書に入れます。 

c,

( byte -- ) 

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

w,

( word -- ) 

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

l,

( quad -- ) 

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

[

( -- ) 

解釈を開始します。 

]

( -- ) 

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

allot

( n -- ) 

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

>body

( xt -- a-addr ) 

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

body>

( a-addr -- xt ) 

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

compile

( -- ) 

次のワードを実行時にコンパイルします。(代わりに postpone を使用するよう推奨します。)

[compile]name

( -- ) 

次の (すぐ次の) ワードをコンパイルします。(代わりに postpone を使用するよう推奨します。)

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 に置き換えます。

postpone name

( -- ) 

ワード name の実行を遅らせます。

recurse

( ... -- ??? ) 

コンパイル中のワードへの再帰呼び出しをコンパイルします。 

recursive

( -- ) 

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

state

( -- addr ) 

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

表 4-17に示す辞書コンパイル用コマンドは 64 ビットの OpenBoot 実装専用です。

表 4-17 64 ビット辞書コンパイルコマンド

コマンド 

スタックダイアグラム 

説明 

x,

( o -- ) 

octlet、o をコンパイルして辞書に入れます (doublet 境界)。

数値の表示

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

表 4-18 基本数値表示

コマンド 

スタックダイアグラム 

説明 

.

( n -- ) 

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

.r

( n size -- ) 

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

.s

( -- ) 

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

showstack

( ??? -- ??? ) 

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

noshowstack

( ??? -- ??? ) 

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

u.

( u -- ) 

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

u.r

( u size -- ) 

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

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

基数の変更

数値を特定の基数で出力することや、表 4-19に示すコマンドを利用して演算の基数を変更することもできます。

表 4-19 基数の変更

コマンド  

スタックダイアグラム 

説明 

.d

( n -- ) 

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

.h

( n -- ) 

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

base

( -- addr ) 

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

decimal

( -- ) 

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

d# number

( -- n ) 

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

hex

( -- ) 

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

h# number

( -- n ) 

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

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


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-20にテキスト入力制御用のコマンドを示します。

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

コマンド 

スタックダイアグラム 

説明 

( ccc )

( -- ) 

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

¥ rest-of-line

( -- ) 

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

ascii ccc

( -- char ) 

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

accept

( addr len1 -- len2 ) 

コンソールの入力デバイスから編集された入力行を獲得し、addr に格納します。len1 は許容される最大長です。len2 は実際に受け取られる長さです。

expect

( addr len -- ) 

コンソールから入力行を獲得して表示し、 addr に格納します。(代わりに accept を使用するよう推奨します。)

key

( -- char ) 

入力デバイスのキーボードから 1 文字を読みます。 

key?

( -- flag ) 

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

parse

( char -- str len ) 

入力バッファーからの、char で区切られたテキストを構文解析します。

parse-word

( -- str len ) 

入力バッファーからの、空白文字で区切られたテキストを、先行空白文字を読み飛ばして構文解析します。 

word

( char -- pstr ) 

入力文字列から char で区切られる文字列を集め、メモリー位置 pstr に入れます。(代わりに parse を使用するよう推奨します。)

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


注 -

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


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

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

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

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

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

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

コマンド 

スタックダイアグラム 

説明 

." 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-22にテキスト文字列操作用のコマンドを示します。

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

コマンド 

 

スタックダイアグラム 

説明 

",

( addr len -- ) 

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

" ccc"

( -- addr len ) 

翻訳結果またはコンパイル結果の入力ストリーム文字列をまとめます。 

." ccc"

 

文字列 cccを表示します。

.( ccc)

( -- )  

文字列 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 に格納します。

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 

コロン定義の外部に " を使用すると、それぞれ最高 80 文字までの解釈済み文字列を 2 つしか同時にアセンブルできません。この制限はコロン定義には当てはまりません。

入出力先の変更

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

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

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

コマンド  

スタックダイアグラム 

説明 

input

( device -- ) 

入力用のデバイス、たとえば ttyakeyboard、または device-specifier を選択します。

io

( device -- ) 

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

output

( device -- ) 

出力用のデバイス、たとえば ttyakeyboard、または 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 の前にも screenttyattyb または device-specifier のどれか 1 つを入れます。たとえば、通常のディスプレイ画面でなく、シリアルポートに出力を送る場合は、次のように入力します。


ok ttya output
ok

通常のディスプレイ画面は応答の ok プロンプトを表示せず、シリアルポートに接続されている端末が ok プロンプトと以降のすべての出力を表示されます。

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


ok ttya io
ok 

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


ok " /sbus/cgsix" output

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


ok " screen" output

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

コマンド行エディタ

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

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

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

操作キー 

 

説明 

Return (Enter) 

現在の行の編集を終了し、カーソルの現在の位置に関係なく、表示されている 1 行全部をインタプリタに渡します。 

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-25にコマンド行履歴拡張用のキーを示します。

表 4-25 コマンド行履歴用キー操作コマンド

操作キー 

説明 

Control-P 

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

Control-N 

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

Control-L 

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

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

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

表 4-26 コマンド補完用キー操作コマンド

操作キー 

説明 

Control-Space 

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

Control-? 

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

Control-/ 

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

条件フラグ

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

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

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

表 4-27 比較コマンド

コマンド  

スタックダイアグラム 

説明 

<

( 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 の場合 true (さらにフラグを反転します)。

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 構造

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

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

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

コマンド 

スタックダイアグラム 

説明 

if

( flag -- ) 

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

else

( -- ) 

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

then

( -- ) 

ifelsethen を終了します。

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


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

または


flag if
	(true の場合これを実行)
else
	(false の場合これを実行)
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 コマンドが、複数の候補のなかから代替実行フローを選択するために用意されています。このコマンドの方が、深く入れ子になった ifthen コマンドよりも読みやすいという利点があります。

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

表 4-29 case 文コマンド

コマンド 

スタックダイアグラム 

説明 

case

( selector -- selector )  

caseendcase 条件付き構造を開始します。

endcase

( selector -- ) 

caseendcase 条件付き構造を終了します。

endof

( -- ) 

caseendcase 条件付き構造内の ofendof 句を終了します。

of

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

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

次に 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-30に条件付きループの実行制御用のコマンドを示します。

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

コマンド  

スタックダイアグラム 

説明 

again

( -- ) 

beginagain 無限ループを終了します。

begin

( -- ) 

Begin a beginwhilerepeatbeginuntil、または beginagain ループを開始します。

repeat

( -- ) 

beginwhilerepeat ループを終了します。

until

( flag -- ) 

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

while

( flag -- ) 

flag が true の間、 beginwhilerepeat ループの実行を続けます。

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


begin any commands flag until

および


begin any commands flagwhile
more commands	 repeat

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

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

beginwhilerepeat の場合は、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-31にカウント付きループの実行制御用コマンドを示します。

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

コマンド  

スタックダイアグラム 

説明 

+loop

( n -- ) 

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

?do

( end start -- ) 

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

?leave

( flag -- ) 

flag がゼロ以外の場合、doloop から抜けます。

do

( end start -- ) 

doloop を開始します。インデックスは start から end-1 まで使用されます。

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

i

( -- n ) 

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

j

( -- n ) 

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

leave

( -- ) 

doloop から抜けます。

loop

( -- ) 

doloop を終了します。

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


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 

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-32に、前記以外のプログラム実行制御用のコマンドについて説明します。

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

コマンド 

スタックダイアグラム 

説明 

abort

( -- ) 

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

abort" ccc"

( abort? -- ) 

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

eval

( addr len -- ) 

addr len から Forth のソースを解釈します。 

execute

( xt -- ) 

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

exit

( -- ) 

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

quit

( -- ) 

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

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

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