Tatara

第8章
式

命令や疑似命令が数を必要とする場所には、どこでも式 (expression)を書くことができます。式とは、数、名前、またはそれらを組み合わせた計算のことで、10、msg、msg+2、(count-1)*4などがその例です。TATARAは、その行をアセンブルするときに式の値を計算します。この章では、数と文字の書き方、演算子の働きと計算の順序、そして式が持つ値の種類を説明します。例には、それぞれの式の値を2バイトで格納するDWを使います(11章)。

8.1 値は16ビット

TATARAが計算する値は、すべて0から65535(0FFFFh)までの16ビットの数です。どちらかの端を越える計算は、反対側に回り込みます。65535+1は0になり、0-1は0FFFFhになります。そのため、負の数は、Z80自身が扱うのと同じように、16ビットの補数として格納されます。-1は0FFFFh、-6は0FFFAhです。

ld a,…やDBのオペランドのように、1バイトしか必要としない場所では、TATARAは値の下位バイトを使います。そこで受け付けられる値については、9章と11章で説明します。

8.2 数

数は、表8.1のように、後ろに付けた文字がほかの基数を示さないかぎり、10進数です。この文字は大文字でも小文字でもかまいません。

基数 接尾辞 例 値
10進数 なし、またはD 100、100d 100
16進数 H 100h 256
8進数 OまたはQ 100o、100q 64
2進数 B 100b 4
表 8.1: それぞれの基数の数

数は必ず数字で始まります。英字で始まる語は名前です(7章)。そのため、最初の桁が英字になる16進数には、前に0を付ける必要があります。0ffhは255ですが、ffhは名前なので、定義していなければTATARAは次のように表示して止まります。

HEXNAME.AS(2): ERROR: undefined symbol in an expression.
 

警告.  BとDは16進数の数字であり、接尾辞でもあります。どちらかで終わる数は、2進数または10進数として読まれます。10bは10Bhではなく2です。16進数は、0abhや12bhのように、必ずHで終えてください。

12bの2のように、その基数にない数字があると、TATARAは止まります。

BADDIGIT.AS(2): ERROR: bad expression.
 

8.3 文字

文字定数(character constant)は、アポストロフィーまたは引用符で囲んだ1文字か2文字です。その値は文字のコードで、’A’と"A"はどちらも41hです。2文字の場合は、最初の文字が上位バイトに入るので、"AB"は4142hになります。

2種類の引用符は同じ働きをするので、囲みたい文字がそのどちらかのときに便利です。"’"はアポストロフィーです。また、定数の中では、それを囲んでいる記号を2つ続けて書くと、その記号そのものを表します。そのため、””もアポストロフィーです。

3文字以上の文字列はDBで使います(11章)。

8.4 名前とロケーション・カウンター

式の中の名前は、その値を表します。ラベルのアドレス、またはEQUやDEFLで与えた数です(12章)。TATARAはソースを2回読むので、名前は定義する行より前でも使えます。次のソースでは、jp laterが正しくアセンブルされます。

                cseg 
                jp      later           ; defined below 
later:          ret
 

どこにも定義されていない名前があると、TATARAは止まります。

UNDEF.AS(2): ERROR: undefined symbol in an expression.
 

$だけのときは、ロケーション・カウンター (location counter)を表します。これは、その行のいまのセグメントでのアドレスです(10章)。よく使われるのはjr $で、自分自身にジャンプして、そのまま待ち続けます。

8.5 演算子

演算子を表8.2に示します。英語の単語で書く演算子は、大文字でも小文字でも書けますが、両側にスペースかかっこが必要です。aandbではなくa and bと書きます。

演算子

働き

例と値
+ -

加算、減算

10-4-3 = 3
* /

乗算、除算

17/5 = 3
MOD

除算の余り

17 mod 5 = 2
SHL SHR

左シフト、右シフト

1 shl 4 = 10h
AND OR XOR

ビットごとの論理積、
論理和、排他的論理和

0f0h and 3ch = 30h
NOT

すべてのビットを反転

not 0 = 0FFFFh
HIGH LOW

上位バイト、下位バイト

high 1234h = 12h
EQ NE

等しい、等しくない

1 eq 1 = 0FFFFh
LT LE

より小さい、以下

2 le 1 = 0
GT GE

より大きい、以上

2 gt 1 = 0FFFFh
-(値の前)

符号反転

-1 = 0FFFFh
表 8.2: 演算子

いくつかの演算子には、補足が必要です。

8.5.1 優先順位

演算子が2つ以上ある式では、それぞれの優先順位 (precedence)によって、どれを先に計算するかが決まります。表8.3に、結び付きの強いものから順にその段階を示します。同じ段階の演算子は左から右へ計算されるので、10-4-3は(10-4)-3です。かっこを使うと順序を変えられます。2+3*4は 14で、(2+3)*4は20です。

段階 演算子
1 HIGH LOW
2 * / MOD SHL SHR
3 値の前の-
4 + -
5 EQ NE LT LE GT GE
6 NOT
7 AND
8 OR XOR
表 8.3: 演算子の優先順位(結び付きの強い順)

これはM80と同じ段階です。覚えておくとよいことが2つあります。-2*3は-(2*3)で、not a eq bはnot (a eq b)です。迷ったときは、かっこを付けてください。かっこには何の負担もありません。

8.6 値の種類

2章で説明したように、TATARAはすべてのアドレスを知ることはできず、TANRENが埋めるための穴を残します。そのため、どの式も、値だけでなく種類を持っています。

アブソリュート

10、’A’、EQUで定義した名前のように、TATARAがアセンブルした時点で完成している数です。このような値をアブソリュート(absolute)といいます。

リロケータブル

コード・セグメントのラベルのような、セグメントの中のアドレスです。TATARAが知っているのはセグメントの先頭からの距離だけで、セグメントを置いたアドレスはTANRENが加えます。

外部

EXTRNで宣言した、ほかのモジュールが定義する名前です。TATARAはその値について何も知らず、TANRENが埋めます。

式が役に立つのは、TANRENがアドレスを1つ加えるだけで完成させられる場合だけです。そのため、TATARAが受け付けるのは表8.4の組み合わせだけです。それ以外は、両側ともアブソリュートでなければなりません。

式

結果 例

アブソリュート+リロケータブル、
またはその逆

リロケータブル a1+2

リロケータブル−アブソリュート

リロケータブル a1-2

リロケータブル−リロケータブル
(同じセグメント)

アブソリュート a2-a1

外部+アブソリュート、またはその逆

外部 far+2

外部−アブソリュート

外部 far-2
表 8.4: TATARAが受け付ける組み合わせ

このうちもっとも役に立つのは、同じセグメントの2つのラベルの差です。これは長さを表し、セグメントをどこに置いても変わりません。次のソースでは、a2-a1は1、a1+2はa1の2バイト後ろのアドレスですが、a1*2はコードを移動すると意味がなくなります。

                cseg 
a1:             nop 
a2:             nop 
                dw      a2-a1           ; absolute: 1 
                dw      a1+2            ; relocatable 
                dw      a1*2            ; not allowed
 
RELOC.AS(6): ERROR: relocation error - a segment-relative value is not allowed here.
 

外部の名前は、1つの式の中で1回だけ、数を加えるか引くかして使えます。2-farは受け付けられません。

EXTRN.AS(5): ERROR: an external symbol may not be used here.
 

符号反転、NOT、HIGH、LOWにも、アブソリュートの値が必要です。また、セグメントはそれぞれが1つの種類なので、別々のセグメントにある2つのラベルを引き算することもできません(10章)。