转载自: http://hi.baidu.com/younthu/blog/item/75b8946d0e28bdff4216944a.html
用伪指令实现的分支结构
为了改善汇编语言源程序的结构,减少显式转移语句所带来混乱,在宏汇编MASM 6.11系统中,增加了表达分支结构的伪指令。该伪指令的书写格式与高级语言的书写方式相类似,汇编程序在汇编时会自动增加转移指令和相应的标号。理解并掌握该知识,对将来学习《编译原理》课程也有一定的帮助。
分支伪指令的具体格式如下:
格式1:
.IF condition ;以英文“句号”开头
指令序列 ;条件"condition"成立时所执行的指令序列
.ENDIF
格式2:
.IF condition
指令序列1
.ELSE
指令序列2 ;条件"condition"不成立时所执行的指令序列
.ENDIF
格式3:
.IF condition1
指令序列1
.ELSEIF condition2
指令序列2 ;条件"condition2"成立时所执行的指令序列
.ENDIF
其中:条件表达式“condition”的书写方式与C语言中条件表达式的书写方式相似,也可用括号来组成复杂的条件表达式。
条件表达式中可用的操作符有:==(等于)、!=(不等)、>(大于)、>=(大于等于)、<(小于)、<=(小于等于)、&(位操作与)、!(逻辑非)、&&(逻辑与)、||(逻辑或)等。
若在条件表达式中检测标志位的信息,则可以使用的符号名有:CARRY?(相当于CF==1)、OVERFLOW?(OF==1)、PARITY?(PF==1)、SIGN?(SF==1)、ZERO?(ZF==1)等。例如:
.IF CARRY? && AX != BX ;检测CF==1且AX!=BX是否成立
;汇编语言指令序列
.ENDIF
在指令序列中,还可再含有其它的.IF伪指令,即:允许嵌套。伪指令.ELSEIF引导出另一个二叉分支,但它不能作伪指令块的第一个伪指令。
汇编程序在对“条件表达式”进行代码转换时将进行代码优化处理,以便尽可能生成最好的指令代码。如:
.IF ax == 0
汇编程序会把它转换为指令“OR ax, ax”,而不是“CMP ax, 0”,因为前者比后者更好,而不是简单直接地转换为后者。
如果用伪指令来书写分支结构,那么,例6.5的代码段部分就可写成如下程序段:
… | |||
MOV | AL, CHAR1 | ||
.IF AL>='a' && AL<='z' | ;语句象C语言语句吗? | ||
SUB CHAR1, 20H | |||
.ENDIF | |||
… |
也可把例6.6的代码段部分就可写成如下程序段:
… | ||
MOV AX, X | ||
.IF AX < 0 | ||
ADD AX, 10 | ;计算第一种情况的结果 | |
.ELSEIF AX <= 10 | ||
MOV BX, 30D IMUL BX | ;计算第二种情况的结果 | |
.ELSE | ||
SUB AX, 9 | ;计算第三种情况的结果 | |
.ENDIF | ||
MOV Y, AX … | ;把计算结果保存到变量Y中 |
循环伪指令的格式和含义如下:
1、WHILE型循环伪指令
.WHILE condition
循环体的指令序列 ;条件"condition”成立时所执行的指令序列
.ENDW
其中:.ENDW与前面的.WHILE相匹配,它标志着其循环体到此结束。
如果条件表达式“condition”在循环开始时,就为“假”(false),那么,该循环体一次也不会被执行。
2、REPEAT型循环伪指令
.REPEAT 循环体的指令序列 .UNTIL condition | .REPEAT 循环体的指令序列 .UNTILCXZ [condition] |
REPEAT型循环在执行完循环体后,才判定逻辑表达式condition的值。若该表达式的值为真,则终止该循环,并将执行伪指令.UNTIL[CXZ]后面的指令,否则,将向上跳转到伪指令.REPEAT之后的指令,为继续执行其循环体作准备。
如果.UNTILCXZ后面没有写逻辑表达式,那么,由.REPEAT-.UNTILCXZ所构成的循环与用LOOP指令所过程的循环是一致的,它们都是以“CX=0”为循环终止条件。
如果.UNTILCXZ后面书写了逻辑表达式,那么,该逻辑表达式的形式只能是:“EXP1==EXP2”或“EXP1!=EXP2”。所以,这时由“.REPEAT-.UNTILCXZ condition”所构成的循环就与用LOOPNE/LOOPE指令所过程的循环是一致的,它们都是以“condition || CX=0”为循环终止条件。
和高级语言的REPEAT型的循环一样,.REPEAT-.UNTIL[CXZ]的循环体也会至少被执行一次。
.WHILE-.ENDW和.REPEAT-.UNTIL[CXZ]的循环体内还可再含有循环伪指令,这样就构成了循环结构的嵌套。
汇编程序在生产指令代码时会进行代码优化,以便尽可能得到最优化的指令序列。
3、辅助循环伪指令
(1)、终止循环伪指令
.BREAK
.BREAK .IF condition
该伪指令用来终止包含它的最内层循环。前者是无条件终止循环,后者是仅当逻辑表达式condition为真时,才终止循环。
.WHILE 1 | .REPEAT | |
… | … | |
ENDW | .UNTIL 0 |
对于以上二个循环,如果没有指令来终止循环的话,它们都将进入死循环状态,但如果在该层循环体内,存在伪指令“.BREAK .IF condition”的话,那么,当逻辑表达式condition为真时,该循环就会被终止了。
(2)、循环继续伪指令
.CONTINUE
.CONTINUE .IF condition
该伪指令用于直接跳转到包含它的最内层循环的计算循环条件表达式的代码处。前者是无条件转移到计算循环条件表达式的代码处,后者是仅当条件表达式condition为真时,才进行这样的跳转。
辅助循环伪指令.BREAK和.CONTINUE只能在伪指令.WHILE-.ENDW和.REPEAT-.UNTIL的循环体内使用。
例6.12 显示9个数字字母'1'~'9',26个大写字母,和显示任意输入的数字字符,并用按“回车”键来结束本程序的运行。
解:
DATA1 | SEGMENT | |||
MSG1 | DB 13, 10, "Iteration: " | |||
NUM1 | DB '1', "$" | |||
MSG2 | DB 13, 10, "Alphabet: $" | |||
NUM2 | DB 'A', " $" | |||
MSG3 | DB 13, 10, "Type digits, then press ENTER: $" | |||
DATA1 | ENDS | |||
CODE1 | SEGMENT | |||
ASSUME CS:CODE1, DS:DATA1 | ||||
START: | MOV | AX, DATA1 | ||
MOV | DS, AX | |||
MOV | CX, 9 | |||
MOV | AH, 09H | |||
MOV | DX, OFFSET MSG1 | |||
.REPEAT | ||||
INT 21H INC NUM1 | ;显示Iteration: 1,2,~,9 | |||
.UNTILCXZ | ||||
MOV | DX, OFFSET MSG2 | |||
INT | 21H | ;显示字符串"Alphabet:" | ||
MOV | AH, 09H | |||
MOV | DX, OFFSET NUM2 | |||
.REPEAT | ||||
INT 21H INC NUM2 | ;显示当前字母 ;当前字母向后移 | |||
.UNTIL NUM2 > 'Z' | ;显示整个大写字母表 | |||
MOV | AH, 09H | |||
MOV | DX, OFFSET MSG3 | |||
INT | 21H | |||
.WHILE 1 | ;循环条件为永真的循环 | |||
MOV AH, 07H INT 21H | ;不带回显地从键盘读一个字符 | |||
.BREAK .IF AL == 13 | ;如果输入“回车”键,则终止循环 | |||
.CONTINUE .IF (AL<'0') || (AL>'9') | ;如果字符不是数字字符,则继续循环 | |||
MOV DL, AL MOV AH, 02H INT 21H | ;显示所输入的数字字母 | |||
.ENDW | ||||
MOV | AX, 4C00H | |||
INT | 21H | |||
CODE1 | ENDS | |||
END | START |