Tatara

Chapter 8
Expressions

Wherever an instruction or a directive expects a number, you can write an expression: a number, a name, or a calculation made of them, such as 10, msg, msg+2 or (count-1)*4. TATARA works out its value when it assembles the line. This chapter describes how numbers and characters are written, what the operators do and in what order, and what kind of value an expression can have. The examples use DW, which stores the value of each expression as two bytes (chapter 11).

8.1 Values are 16 bits

Every value TATARA calculates is a 16-bit number, from 0 to 65535 (0FFFFh). Arithmetic that goes past either end wraps round: 65535+1 is 0, and 0-1 is 0FFFFh. A negative number is therefore stored as its 16-bit complement, as the Z80 itself treats it: -1 is 0FFFFh, and -6 is 0FFFAh.

Where a line needs only one byte, such as the operand of ld a,… or of DB, TATARA uses the low byte of the value. Chapters 9 and 11 say which values are accepted there.

8.2 Numbers

A number is decimal unless a letter after it names another base, as in table 8.1. The letter can be upper or lower case.

Base Suffix Example Value
decimal none, or D 100, 100d 100
hexadecimal H 100h 256
octal O or Q 100o, 100q 64
binary B 100b 4
Table 8.1: Numbers in each base.

A number always starts with a digit; a word that starts with a letter is a name (chapter 7). A hexadecimal number whose first digit is a letter therefore needs a 0 in front: 0ffh is 255, but ffh is a name, and unless you have defined it TATARA stops with:

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

Warning.  B and D are hexadecimal digits and also suffixes. A number that ends in one of them is read as binary or decimal: 10b is 2, not 10Bh. Always end a hexadecimal number with its H, as in 0abh or 12bh.

A digit that does not belong to the base, such as the 2 in 12b, stops TATARA:

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

8.3 Characters

A character constant is one or two characters between apostrophes or quotation marks. Its value is the character’s code: ’A’ and "A" are both 41h. With two characters the first goes in the high byte, so "AB" is 4142h.

The two kinds of quotation mark work the same way, which is useful when the character is one of them: "’" is an apostrophe. Inside a constant, the mark that encloses it can also be written twice to stand for itself, so ”” is an apostrophe too.

Strings of more than two characters are for DB (chapter 11).

8.4 Names and the location counter

A name in an expression stands for its value: the address of a label, or the number given to it with EQU or DEFL (chapter 12). A name can be used before the line that defines it, because TATARA reads the source twice: in this source, jp later is assembled correctly.

                cseg 
                jp      later           ; defined below 
later:          ret
 

A name that is defined nowhere stops TATARA:

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

$ on its own stands for the location counter: the address of the line it is written in, in the current segment (chapter 10). A common use is jr $, which jumps to itself and waits forever.

8.5 Operators

Table 8.2 lists the operators. The word operators can be written in upper or lower case, and need a space or a bracket on each side: a and b, not aandb.

Operator What it does Example and value
+ - addition, subtraction 10-4-3 = 3
* / multiplication, division 17/5 = 3
MOD remainder of the division 17 mod 5 = 2
SHL SHR shift left, shift right 1 shl 4 = 10h
AND OR XOR bitwise and, or, exclusive or 0f0h and 3ch = 30h
NOT inverts every bit not 0 = 0FFFFh
HIGH LOW high byte, low byte high 1234h = 12h
EQ NE equal, not equal 1 eq 1 = 0FFFFh
LT LE less than, less or equal 2 le 1 = 0
GT GE greater than, greater or equal 2 gt 1 = 0FFFFh
- (before a value) negation -1 = 0FFFFh
Table 8.2: The operators.

A few of them need a word more:

8.5.1 Precedence

When an expression has more than one operator, the precedence of each decides which is worked out first. Table 8.3 lists the levels, the first binding the tightest. Operators on the same level are worked out from left to right, so 10-4-3 is (10-4)-3. Brackets change the order: 2+3*4 is 14, and (2+3)*4 is 20.

Level Operators
1 HIGH LOW
2 * / MOD SHL SHR
3 - before a value
4 + -
5 EQ NE LT LE GT GE
6 NOT
7 AND
8 OR XOR
Table 8.3: Operator precedence, tightest first.

These are M80’s levels. Two consequences are worth knowing: -2*3 is -(2*3), and not a eq b is not (a eq b). When in doubt, add brackets: they cost nothing.

8.6 What kind of value

Chapter 2 explained that TATARA cannot know every address, and leaves holes for TANREN to fill. Every expression therefore has a kind as well as a value:

Absolute.

A number that is complete when TATARA assembles it, such as 10, ’A’ or a name defined with EQU. Such a value is called absolute.

Relocatable.

An address in a segment, such as a label in the code segment. TATARA knows only its distance from the start of the segment; TANREN adds the address where the segment is placed.

External.

A name declared with EXTRN, which another module defines. TATARA knows nothing about its value; TANREN fills it in.

An expression is only useful if TANREN can finish it by adding one address, so TATARA allows only the combinations in table 8.4. Anything else needs both sides absolute.

Expression Result Example
absolute + relocatable, or the reverse relocatable a1+2
relocatable − absolute relocatable a1-2
relocatable − relocatable, same segment absolute a2-a1
external + absolute, or the reverse external far+2
external − absolute external far-2
Table 8.4: The combinations TATARA allows.

The difference of two labels in the same segment is the most useful of these: it is a length, and it does not depend on where the segment is placed. In this source a2-a1 is 1, and a1+2 is the address two bytes after a1, but a1*2 has no meaning once the code is moved:

                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.
 

An external name can be used only once in an expression, with a number added to it or taken away from it. 2-far is refused:

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

Negation, NOT, HIGH and LOW need an absolute value too. Each segment is a kind of its own, so labels in two different segments cannot be subtracted from each other either (chapter 10).