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