この章では、OpenBoot に実装されている Forth プログラミング言語の概要を説明します。Forth プログラミング言語に詳しい読者も、この章の例を確認してください。これらの例には、OpenBoot に関連する特有の情報が含まれています。
OpenBoot に含まれる Forth のバージョンは、ANS Forth に準拠しています。「付録 I 「Forth ワードリファレンス」」に全コマンドのリストを載せてあります。
この章では、読者はユーザーインタフェースの起動、終了手順を知っているものとしています。ok プロンプトで入力したコマンドのためにシステムがハングアップし、キー入力操作で回復できない場合は、正常動作に復帰させるために電源再投入を行う必要があることがあります。
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 ワード名に大文字と小文字の区別はありません。したがって、testa、TESTA、TesTa はすべて同じコマンドを起動します。しかし、習慣によりコマンドは小文字で書きます。
コマンドによっては (たとえば、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 進数) を使用するよう奨励していますが、必ずそうしなければならないわけではありません。したがって、正しく演算されるためにコードが特定の基数に依存する場合は、そのような基数を設定する必要があります。decimal、hex といったコマンドを使用して変更できます。これらのコマンドは、以降の数値の入出力をそれぞれ 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) を削除し、それを表示します。
スタックの内容に影響しないワード (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 |
Forth は、既存ワードの処理から新しいコマンドワードを作成するための簡単な手段を提供します。表 4-4に、利用者定義作成用の Forth ワードを示します。
表 4-4 コロン定義ワード
コマンド |
スタックダイアグラム |
説明 |
---|---|---|
( -- ) |
ワード 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 |
複数行の定義に ] プロンプトを使用するのは、サン・マイクロシステムズ社の実装の特徴です。
スタックダイアグラムはワードの正しい使い方を示します。したがって、そのスタック効果がない場合 (--) であっても、作成する定義ごとに必ずスタックダイアグラムを入れてください。複雑な定義内にはわかりやすいスタックコメントを使用してください。それによって、実行のフローを容易に追跡できます。たとえば、add4 を作成するには、次のように定義できます。
: add4 (n1 n2 n3 n4 -- ) + + + . ; |
または、次のようにも定義できます。
: add4 (n1 n2 n3 n4 -- ) + + + (sum ) . ( ) ; |
「(」(左側括弧) は、それ以降「)」(右側括弧) までのテキストを無視することを意味します。ほかのすべての Forth ワードと同様に、左側括弧の右側には 1 つまたはそれ以上の空白文字が必要です。
表 4-5に示すコマンドは、単精度整数演算を行います。
表 4-5 単精度演算機能
表 4-6に示すコマンドは倍精度数の演算を行います。
表 4-6 倍精度数演算機能
表 4-7に示すコマンドはデータ型の変換を行います。
表 4-7 32 ビットデータ型変換機能
表 4-8に示すデータ型変換用コマンドは 64 ビットの OpenBoot 実装専用です。
表 4-8 64 ビットデータ型変換機能
表 4-9に示すコマンドはアドレス演算を行います。
表 4-9 アドレス演算機能
表 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) 操作を示します。
waddr、qaddr、oaddr は境界の制約をもつアドレスを示します。たとえば、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 メモリーアクセスコマンド
表 4-12に示すメモリーアクセス用コマンドは 64 ビットの OpenBoot 実装専用です。
表 4-12 64 ビットメモリーアクセス機能
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-mem と free-mem の使用例です。
alloc-mem が 4000 バイトのメモリーを割り当てます。その予約領域の開始アドレス (ef7a48) が表示されます。
dump が ef7a48 から始まるメモリー 20 バイトの内容を表示します。
次に、このメモリー領域を値 55 でみたします。
最後に、free-mem が、割り当てられた ef7a48 からの 4000 バイトのメモリーを返します。
ok ok 4000 alloc-mem . ef7a48 ok ok ef7a48 constant temp ok temp 20 dump 0 1 2 3 4 5 6 7 ¥/ 9 a b c d e f 01234567v9abcdef ef7a40 00 00 f5 5f 00 00 40 08 ff ef c4 40 ff ef 03 c8 ..u_..@..oD@.o.H ef7a50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ef7a60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ok temp 20 55 fill ok temp 20 dump 0 1 2 3 4 5 6 7 ¥/ 9 a b c d e f 01234567v9abcdef ef7a40 00 00 f5 5f 00 00 40 08 55 55 55 55 55 55 55 55 ..u_..@.UUUUUUUU ef7a50 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU ef7a60 55 55 55 55 55 55 55 55 00 00 00 00 00 00 00 00 UUUUUUUU........ ok ok temp 4000 free-mem ok |
前項で説明の仮想メモリーアクセス用のオペレータ (コマンド) を使用してデバイスレジスタをアクセスした場合、信頼性が欠けることがあります。デバイスレジスタアクセス用には特別なオペレータ (コマンド) があります。それらのオペレータ (コマンド) の場合は、使用する前にマシンを正しく設定する必要があります。これについての詳細は、『Writing FCode 3.x Programs』を参照してください。
辞書には用意されているすべての Forth ワードが含まれています。ワード定義を使って新しい Forth コマンドを作成します。
ワード定義は 2 つのスタックダイアグラムを必要とします。最初のダイアグラムでは、新しいワードを作成するときのスタック効果を示します。2 番目の (E:) ダイアグラムはそのコマンドが後で実行されるときのスタック効果を示します。
表 4-14に新しい Forth ワードを作成するためのワード定義を示します。
ある Forth コマンドが既存のコマンドと同じ名前で作成されると、新しいコマンドが正常に作成されます。実装によっては 「new-name isn't unique」 というメッセージが表示されます。そのコマンドの以前の使用方法は、影響を受けません。そのコマンド名をそのあとに使用する場合、最新の定義を使用します。コマンド名の同じものはすべて同じ動作をするようにするには、patch を使用して修正してください。(「patch と(patch) の使用方法」を参照してください。)
表 4-14 ワード定義
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 辞書検索コマンド
辞書検索ツールの動作を理解するには、その前に、ワードがどのようにして見えるようになるかを理解する必要があります。ワードを定義するときにアクティブパッケージがあった場合は、新しいワードはその有効パッケージの方法になり、そのパッケージが有効のときしか見えません。dev、find-device というコマンドを使用して、有効パッケージを選択したり、変更することができます。コマンド device-end は、現在有効なパッケージの選択を解除して、有効パッケージをなくします。
ワードを定義するときにアクティブパッケージがなかった場合は、そのワードはグローバルに見ることができます。(つまり、特定のパッケージ専用ではなく、つねに使用可能です)。
辞書検索コマンドは、存在する場合、最初に有効パッケージのワードに対して検索し、次にグローバルに見えるワードに対して検索します。
Forth コマンドの only と also が、どのワードを見えるようにするかを制御します。
.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 辞書コンパイルコマンド
表 4-17に示す辞書コンパイル用コマンドは 64 ビットの OpenBoot 実装専用です。
表 4-17 64 ビット辞書コンパイルコマンド
コマンド |
スタックダイアグラム |
説明 |
---|---|---|
x, |
( o -- ) |
octlet、o をコンパイルして辞書に入れます (doublet 境界)。 |
表 4-18にスタック値表示用の基本コマンドを示します。
表 4-18 基本数値表示
.s コマンドはスタックの内容全体をそのまま表示します。このコマンドはいつでもデバッグ目的に使用して安全です。(これは、showstack が自動的に実行する機能です。)
数値を特定の基数で出力することや、表 4-19に示すコマンドを利用して演算の基数を変更することもできます。
表 4-19 基数の変更
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 テキスト入力制御
コメントは、コードの機能を記述するために、(一般的にテキストファイル内の) Forth ソースコードに使用します。( 左側括弧がコメントを開始する Forth ワードです。右側括弧) の前までの文字はすべて、Forth インタプリタが無視します。スタックダイアグラムは (を使用するコメントとして取り扱われます。
「(」の後に空白文字を入れることを忘れないでください。それによって、「(」はForth ワードとして認識されます。
¥ (バックスラッシュ) はテキスト行末でコメントが終わりになることを示します。
key はキーが押されるまで待ち、押されると、そのキーの ASCII 値をスタックに返します。
ascii は、ascii x の形式で使用され、文字 x の数字コードをスタックに返します。
key? はキーボードを走査して、ユーザーが新たになんらかのキーを押したかどうかを調べ、フラグをスタックに返します。つまり、キーが押されていた場合は true を、押されていない場合は false を返します。フラグの使い方については、「条件フラグ」の説明を参照してください。
表 4-21に汎用のテキスト表示用コマンドを示します。
表 4-21 テキスト出力表示
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 テキスト文字列操作
一部の文字列操作コマンドは、アドレス (それらの文字があるメモリー内の位置) と長さ (文字列の文字数) を指定します。その他のコマンドは、パックされた文字列、または長さを表すバイトを格納するメモリー位置である 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 および output コマンドは、それぞれ、現在の入力および出力用デバイスを一時的に変更します。変更はコマンドの入力時に行われます。システムをリセットする必要はありません。システムリセットまたは電源再投入を行うと、入出力デバイスは NVRAM システム変数 input-device と output-device に指定されているデフォルト設定に戻ります。これらの変数は、必要に応じて変更できます (デフォルトの変更についての詳細は、第 3 章「システム変数の設定」を参照してください)。
inputの前には、keyboard、ttya、ttyb、または device-specifier テキスト文字列のうちのどれか 1 つを入れます。たとえば、入力が現在キーボードから受け入れられていて、入力がシリアルポート ttya に接続されている端末から受け入れられるように変更する場合、次のように入力します。
ok ttya input ok |
この時点で、キーボードは (「Stop-A」以外は) 機能しなくなりますが、ttya に接続されている端末から入力されるテキストはすべて入力として処理されるようになります。すべてのコマンドが通常どおりに実行されます。
キーボードを再び入力デバイスとして使用するには、端末のキーボードを使用して次のように入力します。
ok keyboard input ok |
同様に、output の前にも screen、ttya、ttyb または device-specifier のどれか 1 つを入れます。たとえば、通常のディスプレイ画面でなく、シリアルポートに出力を送る場合は、次のように入力します。
ok ttya output ok |
通常のディスプレイ画面は応答の ok プロンプトを表示せず、シリアルポートに接続されている端末が ok プロンプトと以降のすべての出力を表示されます。
io も、入出力の両方を指定した場所に変更する点以外、同じ方法で使用されます。
ok ttya io ok |
一般的に、input、output、io の引数には device-specifier を指定する必要があります。device-specifier はデバイスパス名、デバイスの別名のどちらでもかまいません。次の 2 つの例に示すように、デバイスは、二重引用符(") を使用して Forth の文字列として次のように指定する必要があります。
ok " /sbus/cgsix" output |
または、次のように指定します。
ok " screen" output |
上の 2 例では、keyboard、screen、ttya、ttyb は定義済みの 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」を押すと、システムは次のように応答します。
システムが一致ワードを 1 つだけ検索した場合は、ワードの未入力部分が自動的に表示されます。
システムは、一致候補を複数検索した場合は、すべての候補のすべての共通文字を表示します。
システムは、入力した文字に一致する文字を検索できなかった場合は、残りの文字との一致が 1 つ以上現れるまで、右側から文字を削除します。
システムは、正しい候補を判定できない場合は、警報音を鳴らします。
表 4-26にコマンド補完拡張用のキーを示します。
表 4-26 コマンド補完用キー操作コマンド
操作キー |
説明 |
---|---|
Control-Space |
現在のワードの名前を補完します。 |
Control-? |
現在のワードのすべての一致候補を表示します。 |
Control-/ |
現在のワードのすべての一致候補を表示します。 |
Forth の条件付き制御コマンドはフラグを使用して真/偽の値を示します。フラグは、テスト基準に基づいて、いくつかの方法で生成できます。生成できたら、ワード "." でスタックから表示したり、条件付き制御コマンドの入力として使用できます。条件付き制御コマンドは、フラグが真 (true) の場合と偽 (false) の場合にそれぞれ異なる応答を表示します。
表示値が 0 の場合は、フラグの値が false であることを示します。-1 またはその他のゼロ以外の任意の数値は、フラグが true であることを示します。
表 4-27に、比較テストを実行し、true または false フラグの結果をスタックに残すコマンドを示します。
表 4-27 比較コマンド
> はスタックから 2 つの数値を取り出し、最初の数値が 2 番目の数値より大きかった場合は true (-1) をスタックに返し、そうでなかった場合は false (0) を返します。次に例を示します。
ok 3 6 > . 0 (3 は 6 より大きくない) ok |
0= はスタックから 1 項目を取り出し、その項目が 0 であった場合は true を返し、そうでなかった場合は false を返します。このワードはどちらのフラグもその反対の値に反転します。
以降の各項では、Forth プログラム内の実行フローの制御用のワードについて説明します。
if、else、then の 各コマンドは組み合わされて単純な制御構造を作ります。
表 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 コマンドが、複数の候補のなかから代替実行フローを選択するために用意されています。このコマンドの方が、深く入れ子になった ifthen コマンドよりも読みやすいという利点があります。
表 4-29に条件付き case コマンドを示します。
表 4-29 case 文コマンド
次に 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 ループは、特定の条件が満たされるまで、同じコマンドの実行を繰り返します。そのようなループのことを条件付きループといいます。
表 4-30に条件付きループの実行制御用のコマンドを示します。
表 4-30 begin (条件付き) ループコマンド
次に 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 ループは、通常、指定した終了値に達する直前に終了します。
表 4-31にカウント付きループの実行制御用コマンドを示します。
表 4-31 do (カウント付き) ループコマンド
次の画面で、ループの使用方法をいくつか示します。
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" は 2 点を除いて abort と同じです。第 1 点は、フラグが true の場合にスタックからフラグを削除し、その後は何もしないで強制終了させることです。もう 1 点は、強制終了が行われたとき、なんらかのメッセージを表示することです。
eval は (アドレスと長さにより指定された) 文字列をスタックから取り出します。次に、キーボードから入力される場合と同様に、その文字列の文字が解釈されます。Forth のテキストファイルをメモリーに読み込んでいる (第 5 章「プログラムの読み込みと実行」を参照) 場合は、eval を使用してそのファイル内の定義をコンパイルできます。