今どきのデスクトップ・コンピューターで Gforth を実行すると、 特定のサービスを提供するオペレーティング・システムの制御下で Gforth が実行されます。 これらのサービスの 1 つはファイル・サービスです。 これにより、Forth のソース・コードとデータをファイルに保存し、 Gforth に読み込むことができます(see Files)。
伝統的に、 Forth は、 オペレーティング・システムを介さずに基盤となるハードウェアと直接インターフェイスするシステム上で有用なプログラミング言語でした。 Forth は、 そのようなシステム上で大容量ストレージにアクセスするためのブロック(blocks)と呼ばれるメカニズムを提供します。
ブロックは 1024 バイトのデータ領域であり、 データまたは Forth ソース・コードを保持するために使用できます。 ブロックの内容に構造は課されません。 ブロックはその番号によって識別されます。 ブロックには、1 から実装定義の最大値まで連続した番号が付けられます。
ブロックを使用するが、 オペレーティング・ステムを使用しない一般的なシステムでは、 大容量ストレージとして 1 台のフロッピー・ディスク・ドライブを使用し、 ディスクは 256 バイトのセクターを提供するようにフォーマットされます。 ブロックは、 ディスクの容量の制限まで、 ディスクの最初の 4 セクタをブロック 1 に割り当て、 次の 4 セクタをブロック 2 に割り当てることによって実装されます。 ディスクにはファイル・システム情報は含まれず、 ブロック達のみが含まれます。
ファイル・サービスを提供するシステムでは、 ブロックは通常、単一のブロック・ファイル内に一連のブロックを格納することによって実装されます。 ブロック・ファイルのサイズは、 含まれるブロックの数に対応する 1024 バイトの正確な倍数になります。 これが Gforth が使用するメカニズムです。
一度に開くことができるブロック・ファイルは 1 つだけです。 ブロック・ファイルを指定せずにブロック・ワードを使用すると、 Gforth はデフォルトでブロック・ファイル blocks.fb を使用します。 Gforth は、 ブロック・ファイルを見つけようとするときに Forth 検索パスを使用します(see Source Search Paths)。
プログラム制御下でブロックの読み取りと書き込みを行う場合、 Gforth は中間ストレージとして多数のブロック・バッファー(block
buffers)を使用します。 load
を使用してブロックの内容を解釈する場合は、 これらのバッファーは使用されません。
ブロック・バッファーの動作はキャッシュ(cache)の動作に似ています。 各ブロック・バッファーには 3 つの状態(state)があります:
最初は、すべてのブロック・バッファーは「未割り当て」(unassigned)です。 ブロックにアクセスするには、 ブロック(ブロック番号で指定)をブロック・バッファーに割り当てる必要があります。
ブロック・バッファーへのブロックの割り当ては、 block
または buffer
によって行われます。
ブロックの既存の内容を変更する場合は、 block
を使用します。 ブロックの既存の内容を気にしない場合は、 buffer
を使用します29。
block
または buffer
を使用してブロックをブロック・バッファーに割り当てると、
そのブロック・バッファーが「現在のブロック・バッファー」(current block buffer)になります。
データは「現在のブロック・バッファー」内でのみ操作(読み取りまたは書き込み)できます。
「現在のブロック・バッファー」の内容が変更されている場合は、 「block
または buffer
を再度呼び出す前に、」(何もせずに)変更を破棄するか、 update
を使用して、
ブロックを変更済みとしてマークする必要があります(割り当て済・変更中;assigned-dirty)。 update
を使用してもブロック・ファイルは変更されません。
ブロック・バッファーの状態を「割り当て済・変更中」(assigned-dirty)に変更するだけです。 そのブロックは、
そのブロック・バッファーが別のブロックで必要なときに暗黙的に書き込まれるか、 または、 flush
や
save-buffers
によって明示的に書き込まれます。
ワード flush
は、 すべての「割り当て済・変更中」(assigned-dirty)の
ブロックをディスク上のブロック・ファイルに書き込みます。 bye
を指定して Gforth を終了するときは、 flush
も実行されます。
Gforth では、block
と buffer
は direct-mapped
アルゴリズムを使用してブロック・バッファーをブロックに割り当てます。 つまり、 特定のブロックは、
(特定の操作に対して)「いけにえ・バッファー」(victim buffer)と呼ばれる 1
つの特定のブロック・バッファーにのみ割り当てることができます。
いけにえ・バッファーが「未割り当て」(unassigned)状態または「割り当て済・未編集」(assigned-clean)状態の場合、
直ちに新しいブロックが割り当てられます。 「割り当て済・編集中」(assigned-dirty)の場合、 その現在の内容は、
新しいブロックが割り当てられる前に、 ディスク上のブロック・ファイルに書き戻されます。
ブロックの内容に構造は課されていませんが、 伝統的に内容は 1 行当たり 64 文字の 16 行として表示します。 一つのブロックは、 単一の連続した入力ストリームを提供します(たとえば、単一のパース領域として機能します) – ブロック内に行末文字はなく、 ブロックの末尾にファイル終端文字もありません。 これは以下の 2 つの結果をもたらします:
\
というワード – 行末までのコメント – は特別な処理を行います。 ブロックでは、 現在の 64
文字の「1行分」の終わりまでのすべての文字が無視されます。
Gforth では、 存在しないブロック番号を指定して block
を使用すると、 現在のブロック・ファイルが適切なサイズに拡張され、
ブロック・バッファーがスペースで初期化されます。
Gforth にはシンプルなブロック・エディターが含まれています(詳細については use blocked.fb 0 list
と入力してください)。 ただし、ブロックの使用は推奨されません。 このメカニズムは下位互換性のためにのみ提供されています。
ブロックを取り扱うときに使用される一般的な手法は以下のとおりです:
load
する多数の thru
コマンドが含まれています。
ブロックが Forth プログラミング環境にどの程度うまく統合できるかを確認するには、 Frank Sergeant の Pygmy Forth を参照してください。
open-blocks
( c-addr u – ) gforth-0.2 “open-blocks”
c-addr u で指定された名前のファイルをブロック・ファイルとして使用します(訳注: エラーの場合はその時点で throw されます)。
use
( "file" – ) gforth-0.2 “use”
file をブロック・ファイルとして使用します。
block-offset
( – addr ) gforth-0.5 “block-offset”
最初のブロックの番号を含むユーザー変数(0.5.0 以降のデフォルト: 0)。 0.5.0 より前のバージョンの Gforth
で作成されたブロックファイルのオフセットは 1 からです。 これらのファイルを使用する場合は、次のことができます。 1 offset !
または、 使用されるすべてのブロック番号に 1 を加算します。 または、 ファイルの先頭に 1024 文字追加します。
get-block-fid
( – wfileid ) gforth-0.2 “get-block-fid”
現在のブロック・ファイルのファイル ID を返します。 まだブロック・ファイルが開かれていない場合は、 blocks.fb
をデフォルトのブロック・ファイルとして open-blocks
し、
そのファイルID(現在のブロック・ファイルのファイルID)を返します。
block-position
( u – ) block “block-position”
ブロック・ファイル内のファイル位置をブロック番号 u のブロックの先頭に合わせます。
list
( u – ) block-ext “list”
ブロック番号 u のブロックの内容を表示します。 Gforth では、ブロックは 1行 64 文字からなる 16 行の行番号付きで表示されます。
scr
( – a-addr ) block-ext “s-c-r”
このユーザー変数には、 list
によって最後に処理されたブロックのブロック番号が含まれます。
block
( u – a-addr ) block “block”
ブロック番号 u のブロックにブロック・バッファーが既に割り当てられている場合、
そのブロック・バッファーが更新(「割り当て済・変更中」(assigned-dirty)とマークされているか)されているなら、
そのブロック・バッファー内容を当該ブロック(大容量ストレージ)に上書きしてから、 当該ブロックの内容をそのブロック・バッファーに読み込み、
そのブロック・バッファーを「割り当て済・未変更」(assigned-clean)とマークして、 そのブロック・バッファーの開始アドレス
a-addr を返します。 それ以外の場合は、 ブロック u にブロック・バッファーを新たに割り当て、
その新たに割り当てたブロック・バッファーの開始アドレス a-addr を返します。 Gforth では、 buffer
は単に
block
を呼び出します。
buffer
( u – a-addr ) block “buffer”
Gforth では、 buffer
は単に block
を呼び出します。
empty-buffers
( – ) block-ext “empty-buffers”
すべてのブロック・バッファーを「未割り当て」(unassigned)としてマークします。 (update
によって)「割り当て済・変更中」(assigned-dirty)としてマークされているブロックがある場合、 それらのブロックへの変更は失われます。
empty-buffer
( buffer – ) gforth-0.2 “empty-buffer”
update
( – ) block “update”
現在のブロック・バッファー(current block buffer)の状態を「割り当て・ダーティ」(assigned-dirty)としてマークします。
updated?
( n – f ) gforth-0.2 “updated?”
ブロック番号 n のブロックが更新されている(割り当て済・編集中」(assigned-dirty)としてマークされている)なら true を返す。
save-buffers
( – ) block “save-buffers”
更新されている(「割り当て済・変更中」(assigned-dirty)とマークされている)各ブロック・バッファーの内容を大容量ストレージに転送(上書き)し、 すべてのブロック・バッファーを「割当済み・未編集」(assigned-clean)としてマークします。
save-buffer
( buffer – ) gforth-0.2 “save-buffer”
flush
( – ) block “flush”
save-buffers
の機能を実行してから empty-buffers
を実行します。
load
( i*x u – j*x ) block “load”
ブロック番号 u のブロックをテキスト通訳(Text-interpret)します。 ブロック番号 0 のブロックは load
できません。
thru
( i*x n1 n2 – j*x ) block-ext “thru”
ブロック n1 〜 n2 を順番に load
します。
+load
( i*x n – j*x ) gforth-0.2 “+load”
現在のブロック番号に n を足した番号のブロックをロードします。 ブロック内で使います。
+thru
( i*x n1 n2 – j*x ) gforth-0.2 “+thru”
現在のブロック番号 + n1 の番号 〜 現在のブロック + n2 の番号の、 ブロックの範囲をロードします。 ブロック内で使います。
-->
( – ) gforth-0.2 “chain”
ブロック番号 n のブロックのロード中にこのシンボルが見つかった場合、 そのブロックの残りを破棄してブロック n+1 をロードします。
複数のブロックを単一のロード可能なユニットとして連鎖させるために使用されます。 これは ロードの独立性が損なわれるため、 お勧めできません。
代わりに(標準の) thru
または +thru
を使用してください。
block-included
( a-addr u – ) gforth-0.2 “block-included”
load
によって処理されるブロック内で使用します。 現在のブロック・ファイル仕様を保存し、 a-addr u
で指定されたブロック・ファイルを開き、 そのファイルからブロック番号 1 のブロックを load
します(これにより、
他のブロックがチェーンまたはロードされる可能性があります)。 そして最後に、 ブロック・ファイルを閉じて、 元のブロック・ファイルを復元します。
buffer
の標準 Forth での定義は、 ディスク I/O を発生させないことを目的としています。
以前の block
コマンドにより、 特定のブロックに関連付けられたデータがすでにブロック・バッファーに格納されている場合、
buffer
はそのブロック・バッファーを返し、 ブロックの既存のコンテンツが利用可能になります。 それ以外の場合、
buffer
は単にそのブロックに新しい空のブロック・バッファーを割り当てます