格納値の操作


変数を値の代理というよりも格納庫としてみて、そこに格納されている値に直接に演算を施すワードが定義されている。+! と -! である。

+!    ( n addr -- )   \ nをaddrで指された1セル数値に加算する
-!    ( n addr -- )   \ nをaddrで指された1セル数値から減算する

これらは、スタック上の値nを、addrで指定された1セルメモリー領域にある値に対して、それぞれ、足し算、引き算するのである。例えば、

VARIABLE VR1

5 VR1 !
8 VR1 +!  2 VR1 -!
VR1 @   \  11

とすれば、VR1に格納されている値は11である。

VALUEに関しては、forth標準には同様の機能をもつワードは無いようであるが、多くの環境では +TO と -TO が定義されている。もっともMopsではこれらは定義されておらず、 ++> と --> として定義されている。

5 VALUE VL1

8 ++> VL1  2 --> VL1
VL1    \  11

とすれば、上と同値である。

スタック効果を表記すれば、
++>  or  +TO    ( n “<spaces>name” -- )    \ nを“name”で表されるVALUEに加算する
-->  or  -TO    ( n “<spaces>name” -- )    \ nを“name”で表されるVALUEから減算する
である。

もちろん、負の数を加算すれば引き算と同じであり、負の数を減算すれば、その絶対値を足すのと同じである。

変数のメモリーアドレスが出てくるが、そのせいかforthは低級言語だという人もいる(実際は、アドレスはコード面には見えないが)。確かに低級なこともできる。
しかし、forthの方針は機械の動作を記述により明瞭に規定することである。だから低レベルでも隠さないのである。隠さないが故にきちんと記述できるのである。
また、インタープリタやコンパイラを局所的に操作して、抽象的なワード名を付ければ、見た目には極めて高級なことも容易にできるのがforthの特徴である。
抽象度に、階層による分断がないことが、forthの柔軟性のひとつの源泉であり、高級を指向して低レベルへのアクセスを禁止するのは、
せっかくの力を放棄することである。

数値配列の項目値の操作


配列を作った場合でも、1セル配列なら+!, -!によって格納値の増減操作ができる。

CREATE A1 30 CELLS ALLOT
...

5 A1 2 CELLS + +!   \ 2番項目(0ベースなので3つ目)に5を加算
7 A1 7 CELLS + -!   \ 7番項目について7を減算

など。

項目幅が、1バイト、2バイトである場合には、forth標準ではないが、Mopsでは、それぞれ、c+! , c-!、および、w+! , w-!が利用できる。

c+!    ( c c-addr -- )  \ c-addrで指される1バイト数値にcを加算
c-!    ( c c-addr -- )  \ c-addrで指される1バイト数値からcを減算
w+!    ( w w-addr -- )  \ w-addrで指される2バイト数値にcを加算
w-!    ( w w-addr -- )  \ w-addrで指される2バイト数値からcを減算

バイト幅が小さい場合、特に1バイト数の場合には、計算の結果、数値が可能表現範囲をはみ出さないように注意しなければならない。
1バイトは、符号ありでは-128~127の範囲、符号なしでは0~255の範囲。
2バイトは、符号ありでは-32768~32767の範囲、符号なしでは0~65535の範囲。

64ビットMopsでの変数システム


64ビットシステムでは、1セルは8バイトある。Forth標準に文字通りにしたがえば、VARIABLE, VALUE ともに8バイト変数になるはずである。

しかし、Mopsでは当初から32ビットシステムで両変数が4バイトとして扱われてきた歴史は長い。そこで、VARIABLE, VALUEについては4バイト変数に留め、1セル8バイトへの移行に合わせて、あたらしいワード群を導入した。

@XとUVALUE

変数の大きさが4バイトだがスタックセルは8バイトあるわけであるから、VARIABLEやVALUEについても、符号展開をどうするかという問題がでてくる。

VARIABLE

VARIABLEに関しては、1バイトフェッチの場合と平行に、@は符号展開なしのフェッチとし、符号展開するワードとして@Xが導入された。4バイト数の取り出しにおいて正負の符号を保持したいときは、@Xを用いなければならない。
4バイトをq-で表せば、次のようなスタック効果となる:

@X    ( q-addr -- x )    \ q-addrで指された4バイト値を正負のある値としてスタックにコピーする
@     ( q-addr -- u )    \ q-addrで指された4バイト値を正か0の値としてスタックにコピーする

VARIABLE VR2

-1 VR2 !

VR2 @X    \ -- -1
VR2 @    \ -- 4294967295

合わせて、加算、減算ワードも、意味を少し変える。

+!    ( n q-addr -- )    \ q-addrで指された4バイト値にnを加算する
-!    ( n q-addr -- )    \ q-addrで指された4バイト値からnを減算する

VALUE UVALUE

他方、VALUEについては、-1(forthではTRUEを意味する)などのフラグを格納することが多かったため、それ自体は符号を保持するものとし、符号なしの4バイト変数としてUVALUEが導入された。Unsigned(符号なし)VALUEである。構文は、VALUEとおなじである。

0 UVALUE UVL1

-1 -> UVL1
UVL1    \ -- 4294967295


ZVARIABLE, ZVALUE

1セル8バイトデータ領域を持つ変数として、新たに、ZVARIABLEとZVALUEが設けられた。冒頭にZをつけるのである。
ZVARIABLEに関しては、ストア/フェッチも増減操作も、頭にzを付ける。

ZVARIABLE ZV1

-173 ZV1 z!    65 ZV1 z+!   ZV1 z@   \  -- -108

ZVALUEについては、元来のVALUEと全く同じように利用できる。

冒頭に付けるのが、なぜZなのかについては、Mopsの著者であるMichael Horeによれば、IBMの64ビットシステムがZシリーズと呼ばれ、
そこから借りたものである。
では、なぜIBMはZシリーズという呼称にしたのか。これについては、私の憶測ではあるが、Zはラテン文字ではなく、ギリシャ文字のゼータ(大文字Z、小文字ζ)
なのではないか、と思われる。というのは、Zないしζは、ギリシャ文字アルファベットでは、6番目なのである。
64は2の6乗だが、英語では"6乗"を、"6番目のパワー"という言い方をするのである(パワー Power は冪という意味)。

定数(CONSTANT)


便宜上、ここで定数を定義する方法を説明しておく。定数定義は、決まった数値を名前で呼び出せるようにすることで、コードの意味の理解しやすくするためのものである。そのように定義された定数もまた、ひとつのワードとして扱われる。
宣言の構文はVALUEと相似であり、CONSTANTというワードを用いる。
64 CONSTANT 1CellBits
上のように宣言すれば、値が64の定数1CellBitsが定義される。1CellBitsというワード名は、数値64と同視される。
CONSTANT   ( x “<spaces>name” -- )
定数値はスタックから取られるのであるから、どこかで格納した変数でも、何か計算をした結果の値でもかまわない。ただし、定数であるから、スタック値はコンパイル時に確定していなければならないのは当然である。

別のページで説明するビット判定において、フラグビットの意味を分りやすくするために用いられることも多い。

なお、iMopsではCONSTANTは、4バイト符号付き数として定義されている。拡張としてZCONSTANTが定義されている。PowerMops64ではCONSTANTは64bitである。





最終更新:2013年08月04日 10:22