Hex Decimal


数字の表記は、デフォルトでは10進数で解釈される。しかし、モードとして16進数解釈に切り替えられる。そのためのワードがHEXである。
HEX  ( -- ) \ 16進数モードに切り替える
数字はすべて16進数で表記されていると解釈される。したがって、HEXを実行しておけば、コード内に、BEEF とかCafeとかdeadなどと書いても、そのような名前のワードを定義していない限り、数字として解釈される。10進数に戻すには、DECIMALを実行する。
DECIMAL ( -- ) \ 10進モードに切り替える
なお、モードとしてだけではなく、$を付けることで16進数表記の数字であることを示す方法がある。標準forthにおいてはインタープリタの特性として、$の後に空白なく直接続けて数字を書くやり方が導入されている。例えば、
$ABCD \ -- 43981 (10進表記では)
のように書けば、$ABCDという名前のワードが定義されていない限り、16進数の数字と解釈されるわけである。
これに対して、Mopsでは、$をワードとしている。つまり、$の後には空白が必要である。それに続くワードを16進表記の数字と解釈する。
$ ABCD

なお、forthの数字解釈の基数は、グローバルVARIABLEであるBASEによって管理されている。このVARIABLEに格納された数値が基数となる。2から36までの数値が許容されている。36進数というのは、要するに、アルファベットをZまで数字として扱うわけである。適正範囲内かどうかチェックなどはしないのがforthのデフォルトなので、BASEに0のような数字を格納しないように注意しなければならない。
なお、PowerMopsではBASEはVALUEになっているので、! や @ を用いてはならない。iMopsではVARIABLEである。

Mopsのスタックビューでは、モードにかかわらず、常に符号付きの10進表記と16進表記が併記される形で表示される。

なお、forth標準の数値インタープリター拡張は、16進数表記であることを示す$に加えて、10進数と2進数表記の数字であることを示す#%が導入されている。これらはワードではなく符号であるから、続く数値リテラルとの間に空白を入れてはならない。特に#は別途コアワードとして定義され、単独では全く別の機能を持つので、注意を要する。
#3423 \ モードにかかわらず、10進表記の3423であることを示す。
%1101 \ 2進数として解釈される(=13(10進)=D(16進))。
Mopsでは採用されていない。iMopsでは、インライン定義内にリテラルを用いるためにこれらの記法が必要とされている。

実用上は、進数の基数モードの変更は、よほど低レベルなコードを書く必要がある場合以外は利用しない。実際、混乱しやすい。$を用いて局所的に16進表記を用いる以上のことは、アプリケーションプログラムで必要になることは滅多にない。

. (ドット) .R


. は一文字ワードであり、スタック上の値を取り、現在の進数モードでスクリーン上に印字する。ドットと呼ばれる。文字としてはピリオドに使う文字である。
.  ( n -- )
数字は左詰めである。
他方、.Rは表示すべき数と、それを表示する枠の字数の2つの値を取って、枠の中に右詰めで表示する。
.R ( n1 n2 -- )
例えば、枠の桁数を4で統一すれば、
12 4 .R cr 123 4 .R cr 3 4 .R
  12
 123
   3
のように表示されるわけである。.Rにおいても現在のBASEの値が基数として用いられる。数値の桁数が指定された桁数よりも大きいときには、左側に空白を置かず、ただ数字がその桁数のまま表示される。

. は計算結果を表示させるためにも用いられるが、デバッグのときに、値をdupした上で . することによって、ワードの途中で渡されている数値がどうなっているのか検査するために用いたりもする。GUI環境のアプリケーションではあまり使わない(iMopsでは一般のウィンドウに表示するためには使えない)。

.H U. U.R U.H


スタック上の数値を取り出してスクリーンに印字するワードであるが、それぞれ表示様式を特定して表示する。

.Hは、スタックの値を取り出して、それを16進数表示でスクリーンに印字する。
.H ( x -- )  \ 16進数(hexadecimal)表示で数値を印字
例えば、
10 .h
A
のようになるわけである。

U.は、スタック上の値を取るが10進数として印字する。ただし、入力は符号なし数と解釈される。つまり、負の数値リテラルは大きな正数として解釈され表示される。
U. ( u -- ) \ 符号なし数を10進数で印字する
Forthの標準規格は上のようになっていて符号なし数という種類の数値があるかのようである。このような表現になっているのは、符号なし数の最大値に限界があるforth環境の場合、uがその限界を超えているなら動作が保証されないこともありうる、ということであろうか。

U.Rは.Rの符号なし版であり、符号なし数を決まった桁数枠に右詰めで表示するのである。
U.R ( u n -- )

U.Hは、forth標準ではないが、Mopsでは定義されている。内容は、もちろん、U.と.Hの2つの組み合わせであり、符号なしの16進数表記で、スタック上の値を印字するのである。
U.H ( u -- ) 

<# # #S #>


これら暗号のようなワード群は、数値を数字の文字列に変換するためのものである。これらのワードはforthコアとして定められている。しかし、文字列に変換される数値は符号なしダブル整数仕様であることになっている。

ダブル整数とは、スタックの項目を2つ使って整数を表記する方法である。32ビットシステムなら8バイト数(約922京(1019弱))まで、64ビットシステムなら16バイト数(約170澗~1038)まで利用できるようになる。スタック上の表現は、比喩的にいえば「リトルエンディアン」である。つまり、下の方の桁部分に当たる数値をまずスタックに置き、上の方の桁に当たる部分をその上に置く。1セルバイトの範囲内の数値であれば、正の数なら上の桁に当たるトップアイテムは0であり、負の数なら-1である。

<# #>の中で用いられるダブル整数は規格上正の値に限定されているので、取り扱える値を1セル数に限り、上のアイテムは0として切り捨てる扱いをしている環境もあるようである。実際、32ビット環境以上では、ダブル整数の必要性は薄い。16ビットパソコン時代の遺物ともいえる。

ダブル整数の記法は中間にドットを入れる。例えば、123.456とすれば、数値としては123456のダブル整数として解釈される。
この場合、上のセルには0、下のセルには123456が格納される。PowerMopsでは、doubleという名前のオプションファイルを
ロードすれば利用できるが、iMopsではダブル整数のリテラルを読み取る機構は実装されていない。

さて、本題に入る。
<#は数字を文字列に変換する手続に入ることを標すワードである。準備をするだけであり、特にスタック効果はない。
<#   ( -- ) \ 数値の文字列への変換を準備する。
#>は締めくくりをするワードであり、残っているダブル整数のスタック値は落とし、文字列のaddr lenをスタックに置く。
#>  ( ud -- addr len )
符号なしダブル整数はスタックコメントには"ud"と1つしか書かないが、実際のスタックアイテムは2つである。

##Sは、これらの2つのワード<# #>の間でしか意味を持たないワードである。

#は、スタック上のダブル整数をBASEの値で割り、その余りを数字に変換して文字列バッファに格納する。つまり、現在の進数表記で下から1桁ずつ変換していくのが#である。
# ( ud1 -- ud2 ) \ ud1をBASEで割り、ダブル整数の商をスタックに残し、剰余を文字としてバッファに右詰めで格納する。
数字は右詰めになるので、複数個連ねれば、#の個数の桁分を数字文字列に移すことになる。最後の#>は残った数値は捨ててしまうので、例えば、下の5桁しか必要ない場合には、#を5つ書けば良いことになる。その場合、5桁より小さい数値については、5桁になるまで左側に0が詰められることになる。

#Sは、ダブル整数値が0になるまで#を繰り返す。つまり、数値を文字列に変換し切るのである。
#S  ( ud1 -- ud2 ) \ ud1を数字列に変換する。ud2はダブルの0である。

iMopsでは127ビット数まで対応している。ただし、負の数、つまり128ビット目がオンの数を与えると、機械が例外を投げる(デフォルトではクラッシュする)ので注意を要する。また、#や#Sに付いても、<# #>の外で実行した場合の保護は特に設けていない(マシンエクセプションとなる可能性もある)。

例としては、
73 0 <# # # # # #> type
0073
-1 0 <# #S #> type
18446744073709551615 \ 64ビットの場合
のようになる。

ちなみに、iMopsで、
-1 -1 1 >> <# #S #> type
とすると、容易には読めない大きな数値が表示される。

仕上げの#>は、バッファーの数字列のありかを指し示すが、この数字列は、文字列バッファーを用いる他のワードを実行した後には、上書きされてしまう可能性がある(実装に依存する)。特に、<# #>によって生成された数字列は、もう一度<# #>を実行すると消えてしまう可能性がある。したがって、もしも結果を保存しておきたいのであれば、次の使用までに、専用のデータフィールドを確保して、そこに内容をコピーしておかなければならない。文字列のコピーの方法は、別のページで説明するが、MopsならStringオブジェクトにPut:すればよい。

なお、#と#Sは混用もできる。たとえば、あまり意味はないかも知れないが、
345 0 <# 0 0 # # # 2drop #S #> type
345000
765 0 <# #S 98 0 # # 2drop #> type
98765
のように数字を追加して桁を増やすこともできる。

.S


スタックの現状を保持したまま、スタック上の全ての数値についてスクリーンに印字するのが.Sである。表示の様式は実装に依存する。Mopsではやや騒々しく、メッセージ風に表示される。スタックの状態を変化させないので、要所に.Sをおけば、デバッグに便利である。スタックの状態があまり見やすくない環境では、時折、これを用いてもよい。

?


文字化けではなく、クエスチョンマークのワードがあるのである。ワード? は、アドレスを入力として、そこに格納された1セル幅の数値を、スクリーンに印字する。
? ( addr -- )
これは、"@ ."と同値である。これも、デバッグ以外の目的では滅多に使われないように思う。オプショナルワードであり、Mopsでは定義されていない。しかし、Starting ForthやThinking Forthといった有名な本のコード例には出てくる。






最終更新:2019年03月19日 22:46