Forth は伝統的に、 整数の書式設定された出力に「表示数値出力」(pictured numeric Output)
と呼ばれる手法を使用しています。 この手法では、 数値から数字桁(digits)が抽出され(base
で定義された現在の出力基数を使用
see Number Conversion)、 ASCII コードに変換され、
メモリーのスクラッチパッド領域(see Implementation-defined options)に構築される文字列の先頭に付加されます。 抽出プロセス中に、
文字列の先頭に任意の文字を追加できます。 完成した文字列はアドレスと長さによって指定され、 プログラム制御の下で操作(TYPE
や、
コピーや、 変更)できます。
前のセクションで説明したすべての整数出力ワード (see Simple numeric output) は、 Gforth では表示数値出力(pictured numeric output)を使用して実装されています。
表示数値出力(pictured numeric output)について覚えておくべき 3 つの重要な点:
標準 Forth は、 <#
で空にして初期化し、 #>
で結果文字列を取得する単一の出力バッファー(別名ホールド領域;hold area)をサポートします。
Gforth はさらに、 このバッファーの入れ子になった使用をサポートしており、 たとえば、 ホールド領域を処理するコード内でデバッグ・トレーサー
~~
からの出力を入れ子にすることができます。 <<#
は新しい入れ子を開始し、 #>
は結果文字列を生成し、 #>>
は入れ子を解除します。 入れ子のホールド領域が再利用され、#>
は次に外側の入れ子の文字列を生成します。 Gforth の高レベルの数値出力ワードはすべて <<#
... #>
... #>>
を使用し、 ホールド領域の他のユーザー内に入れ子にできます。
<#
( – ) core “less-number-sign”
表示数値出力文字列を 初期化/クリア します(訳注: 表示数値出力用のポインターをホールド領域の末尾(初期値)に戻すだけ。 中身は消さない。)
<<#
( – ) gforth-0.5 “less-less-number-sign”
#>>
で終わるホールド領域を開始します。 相互に入れ子にすることも、 <#
で入れ子にすることもできます。 注:
<<#
と #>>
を一致させないと、 最終的にホールド領域が不足します。 <#
を使用してホールド領域を空にリセットできます。
#
( ud1 – ud2 ) core “number-sign”
<<#
と #>
の間で使用されます。 ud1 の最下位桁(base
による)を、
表示数値出力文字列の先頭に追加します。 ud2 は ud1/base、 つまり残りの桁を表す数値です。
#s
( ud – 0 0 ) core “number-sign-s”
<<#
と #>
の間で使用されます。 ud のすべての数字を表示数値出力文字列の先頭に追加します。
#s
は少なくとも 1 つの数字を変換します。 したがって、 ud が 0 の場合、 #s
は表示数値出力文字列の先頭に ‘0‘ を追加します。
hold
( char – ) core “hold”
<<#
と #>
の間で使用されます。 表示数値出力文字列の前に文字 char を追加します。
holds
( addr u – ) core-ext “holds”
<<#
と #>
の間で使用されます。 表示数値出力文字列の前に文字列 addr u
を追加します。
sign
( n – ) core “sign”
<<#
と #>
の間で使用されます。 n (1倍長整数) が負の場合、 表示数値出力文字列の先頭に
-
を追加します。
#>
( xd – addr u ) core “number-sign-greater”
変換対象(変換残りの)数値 xd を破棄し、 フォーマットされた文字列のアドレスと長さを示す addr u を返すことで、
表示数値出力文字列を完成させます。 標準のプログラムでは、 文字列内の文字を変更する場合があります。 ホールド領域は解放されません。
#>>
を使用して <<#
で始まるホールド領域を解放するか、 <#
を使用してすべてのホールド領域を解放します。
#>>
( – ) gforth-0.5 “number-sign-greater-greater”
<<#
で始まるホールド領域を解放します。
以下に、 表示数値出力の使用例をいくつか示します:
: my-u. ( u -- ) \ PNS(Pictured Number String)の最も単純な使用法。標準の u. のように振る舞います。 0 \ 上記 u を 2倍長にする <<# \ 変換開始 #s \ 全桁を変換 #> \ 変換終了 TYPE SPACE \ 表示、続けて空白1つ #>> ; \ ホールド領域を開放 : cents-only ( u -- ) 0 \ 上記 u を 2倍長整数に変換 <<# \ 変換開始 # # \ 最下位と最下位からの次の 2 桁のみ変換 #> \ 変換完了。他の桁は破棄 TYPE SPACE \ 表示、続けて空白1つ #>> ; \ ホールド領域を開放 : dollars-and-cents ( u -- ) 0 \ 上記 u を符号無し2倍長整数に変換 <<# \ 変換開始 # # \ 下位2桁を変換 '.' hold \ 小数点を打つ #s \ 残りの桁を変換 '$' hold \ 通貨記号を打つ #> \ 変換完了 TYPE SPACE \ 表示、続けて空白1つ #>> ; \ ホールド領域を開放 : my-. ( n -- ) \ 負数も処理する標準の . のように振る舞う s>d \ 符号付き2倍長整数に変換 swap over dabs \ 符号バイトを別途保存して数値は符号無し2倍長に <<# \ 変換開始 #s \ 全桁を変換 rot sign \ 符号チェック。必要なら "-" 付加 #> \ 変換完了 TYPE SPACE \ 表示、続けて空白1つ #>> ; \ ホールド領域を開放 : account. ( n -- ) \ (会計風出力)会計士はマイナス記号が嫌いで、 \ 負の数には括弧を使用します s>d \ 符号付き2倍長整数に変換 swap over dabs \ 符号バイトを別途保存して数値は符号無し2倍長に <<# \ 変換開始 2 pick \ 符号バイトのコピーを得る 0< IF ')' hold THEN \ これが(あれば)出力の右端の文字 #s \ 全桁を変換 rot \ 符号バイトを得る 0< IF '(' hold THEN #> \ 変換完了 TYPE SPACE \ 表示、続けて空白1つ #>> ; \ ホールド領域を開放
これらのワードの利用例をいくつか示します:
1 my-u. 1 ok hex -1 my-u. decimal FFFFFFFFFFFFFFFF ok 1 cents-only 01 ok 1234 cents-only 34 ok 2 dollars-and-cents $0.02 ok 1234 dollars-and-cents $12.34 ok 123 my-. 123 ok -123 my-. -123 ok 123 account. 123 ok -456 account. (456) ok