7、表達式
表達式是程序設計課程里的一個重要的基本概念,它可由運算符、操作符、括號、常量和一些符號連在一起的式子。在匯編語言中,表達式分為:數值表達式和地址表達式。
(1)進制偽指令RADIX
偽指令RADIX用來設置整數的缺省進制,宏匯編開始時所默認的整數進制為十進制。該偽指令的使用格式如下:
.RADIX exp
其中:偽指令前面要用點‘.’開始,exp的值必須是區間[2, 16]內的一個整數。
該偽指令說明其下面整數的默認進制為exp。如果某整數已顯式地表明了其進制,則該默認進制對其不起作用。在源文件中,可以使用多個RADIX偽指令來分別說明其后整數的默認進制,但為了避免引起不必要誤會,我們不提倡這樣去做。
例如:
.radix 8
B1 DB 10, 11, 12 ;這三個數是八進制數
DB 10D ;這數是十進制數,因為它已用'D'明確說明而不使用缺省進制
…
.radix 10
MOV AX, 1234 ;1234是十進制數
MOV AX, 1234H ;1234H是十六進制數
思考題:
.radix 16
DW 90D, 101B ;前者是十進制數,后者是二進制數嗎?(是)
(2)數值表達式
數值表達式是在匯編過程中能夠由匯編程序計算其值的表達式,其組成部分在匯編時就能完全確定。它通常是一些常量的運算組合。
1)常量
常量是一個立即數,直接寫在匯編語言語句中,在程序的執行過程中,它不可能發生變化。通常,我們用二進制、八進制、十進制或十六進制來書寫常量。
例如:10101011B、324Q、1234D、1234H、0abcdH、'AB'等都是常量。
在程序中,我們還可用偽指令.RADIX來改變數據的基數,在后面再詳細講解。
2)算術運算符
算術運算符包括符號:+(正)、-(負),運算符:+(加)、-(減)、*(乘)、/(除)和MOD(取模)。這些運算符和常量、括號可組成數值表達式。
如:120+(321-90) mod 3,322*5/32,0abcdH+5,-590等
3)關系運算符
關系運算符包括符號:EQ(相等)、NE(不等)、LT(小於)、GT(大於)、LE(小於等於)和GE(大於等於)。這些關系運算符和常量、括號也可組成數值表達式。該表達式的計算結果規定如下:
若關系不成立,則該數值表達式的計算結果為0;否則,其結果為0FFFFH。
如:120H LT 100H+3,21H LE 21H等,它們的計算結果分別為:0和0FFFFH。
4)邏輯運算符
邏輯運算符包括按位操作符和移位操作符。具體是:AND(邏輯與)、OR(邏輯或)、NOT(邏輯非)、XOR(異或)、SHL(左移位)和SHR(右移位)。這些邏輯運算符和常量、括號可組成數值表達式。
如:1 SHL 3,47H AND 0FH,NOT 56H等,它們的計算結果分別為:8,7和0A9H。
5)表達式中的其它操作符
匯編語言中,還有其它可在數值表達式中使用的操作符。它們是:
a) HIGH(高8位)、LOW(低8位)
b) SEG(段地址)、OFFSET(偏移量)
c) TYPE(標識符類型)、LENGTH(變量長度)、SIZE(變量容量)
d) WIDTH(記錄/記錄字段寬度)、MASK(記錄/記錄字段的屏蔽位)等
在以上操作符中,只有HIGH和LOW沒有介紹過,它們分別是選取表達式計算結果的高8位和低8位。其使用格式如下:
HIGH 表達式 LOW 表達式
如:HIGH (1234H+100H),LOW 1234H等,它們的選取結果分別為:13H和34H。
6)運算符和操作符的優先級
在匯編語言中,有許多各種運算符和操作符,它們的優先級按從高到低的排列如下:
優先級:高 → 低
LENGTH、SIZE、WIDTH、MASK、()、[]、.(用於結構字段)、<>(用於記錄類型)
PTR、SEG、OFFSET、TYPE、THIS、:(用於段超越前綴)
*、/、MOD、SHL、SHR
HIGH、LOW
+、-
EQ、NE、LT、LE、GT、GE
NOT
AND
OR、XOR
SHORT
這些符號及其優先級並不要強記它們,有些符號同時出現的可能性非常小。在以后的學習中對常用的幾個加以運用也就記住了。
(3)地址表達式
地址表達式是計算存儲單元地址的表達式,它可由標號、變量名和由括號括起來的基址或變址寄存器組成。其計算結果表示一個存儲單元的地址,而不是該存儲單元的值。
例如:
B1 DB 10H, 11H, 12H
DB 'ABCD'
W1 DW 1234H, 5678H
表達式B1+1、B1+3和W1+2等都是地址表達式,其值所代表的地址位置如圖4.10所示。顯然這些地址表達式所對應的存儲內容分別為:11H、'A'和5678H。
注意:地址表達式W1+1並不表示字變量W1之后一個字的存儲單元,而是字變量W1之后一個字節的存儲單元,它的存儲單元值是:7812H。
8、符號定義語句
在程序中,我們經常要使用一些常量或數值表達式,並把它們直接寫在指令中,但當需要修改時,就要對它們逐個進行修改,這無疑會增加維護程序的工作量,而且每個常量或表達式所代表的含義也容易遺忘。
為了改善程序的可讀性,盡量減少維護程序的工作量,匯編語言提供了為常量或表達式定義一個符號名的方法。一旦定義了符號名,在指令中就可直接使用它們。(就像C語言的#define宏定義)
(1)等價語句
1)一般格式
等價語句的一般使用格式如下:
符號名 EQU 表達式
作用是左邊的符號名代表右邊的表達式。
注意:等價語句不會給符號名分配存儲空間,符號名不能與其它符號同名,也不能被重新定義。
2)用符號名代表常量或表達式
當把一個常量或表達式定義成一個具有一定含義的符號名后,在程序中就可以用該符號名來代表該常量或表達式。
例如:
NUMBER EQU 100 ;給緩沖區的長度取一個符號名
BUFF_LEN EQU NUMBER+2
CR EQU 13 ;給“回車”符的ASCII碼定義一個符號名
LF EQU 10 ;給“換行”符的ASCII碼定義一個符號名
…
BUFFER DB NUMBER, ?, NUMBER DUP (?) ;用符號名來定義緩沖區
…
3)用符號名代表字符串
用一個具有一定含義的符號名定義某一個較長的字符串,在隨后的程序中就用該符號名。例如:
GREETING EQU "How are you!"
在該定義之后,就可使用符號名GREETING來代表字符串"How are you!"。
4)用符號名關鍵字或指令助憶符
用一個(組)程序員自己習慣的符號名來代替匯編語言中的關鍵字或指令助憶符。但在此建議不要這樣做,因為程序的編寫者習慣,程序的其他閱讀者可能會覺得很別扭。
例如:
MOVE EQU MOV ;給指令MOV取另一個符號名MOVE
COUNTER EQU CX ;給寄存器CX取一個叫“計數器”的符號名
上面的定義只是給原來的助憶符MOV和CX起了另一個別名,而原來助憶符MOV和CX仍然可以使用,所以,我們可編寫如下語句:
MOVE AX, CX ;相當於指令:MOV AX, CX
MOV COUNTER, BX ;相當於指令:MOV CX, BX
5)用符號名定義存儲單元的別名
可對一片存儲單元定義另一個數據類型的符號名,有關敘述參見前面的操作符THIS。
例如:
WORD1 EQU THIS WORD ;給后面的字節存儲單元取一個字屬性的符號名
BYTE1 DB 12h, 21h
FLAG DW 1234H
FLAG1 EQU byte ptr FLAG ;給FLAG的低字節取一個字節屬性的符號名
FLAG2 EQU byte ptr FLAG+1 ;給FLAG的高字節取一個字節屬性的符號名
有了上述定義后,可編寫如下語句:
MOV AX, WORD1 ;執行后,(AX)=2112H
MOV BL, FLAG1 ;執行后,(BL)=34H
(2)等號語句
匯編語言提供了用等號來定義符號常數的方法,即可用符號名代表一個常數。其一般格式如下:
符號名=數值表達式
數值表達式在匯編時應該可以計算出數值,它不能含有向前引用的符號名稱。用等號語句定義的符號可以被重新定義。例如:
ABC = 10 + 200 * 5 ;ABC的值為1010
ABC1 = 5 * ABC + 21 ;ABC1的值為5071
COUNT = 1 ;COUNT的值為1
COUNT = 2*COUNT + 1 ;COUNT的值為3
符號名定義語句LABEL與前面的操作符THIS功能類似,該語句定義一個指定的符號名,該符號名的段地址和偏移量與下面緊跟存儲單元的相應屬性相同,但該符號的類型是新指定的。LABEL語句的一般格式如下:
符號名 LABEL 類型
其中:常用的類型有BYTE、WORD、DWORD、NEAR和FAR等。
例如:
…
WBUFFER LABEL WORD
BUFFER DB 200 DUP(0)
…
NEXT1 LABEL FAR
NEXT: MOV AX, BX
WBUFFER與BUFFER具有相同的段地址和偏移量,但它們的數據類型不同。
NEXT1和NEXT具有相同的段地址和偏移量,NEXT1是“遠”標號,NEXT是“近”標號。
標號NEXT1和NEXT可用於不同的情況。當在同一個模塊內轉移時,可使用標號NEXT;當在不同的模塊之間進行轉移時,需要使用“遠”標號NEXT1。

