分支程序的基本思想是根據(jù)邏輯判斷的結果來形成程序的分支,如圖,若a成立,則執(zhí)行p1;否則執(zhí)行p2。
分支程序有兩種基本結構,如圖所示。
它們分別相當于高級語言中的if_then_else語句和case語句,適用于要求根據(jù)不同條件作不同處理的情況。if_then_else語句可以引出兩個分支,case語句則可以引出多個分支,不論哪一種形式,它們的共同特點是:運行方向是向前的,在某一種特定條件下,只能執(zhí)行多個分支中的一個分支。
例1試編寫程序段,實現(xiàn)符號函數(shù)。
分析:變量x的符號函數(shù)可表示為:
程序可通過對符號標志的判別來確定執(zhí)行哪一分支。
start: mov ax,buffer;(buffer)=x
orax,ax
jezero??;x=0,則轉zero
jnsplus;x為正數(shù),則轉plus
mov bx,0ffffh?。粁為負數(shù),則-1送bx
jmpcont1
zero:mov bx,0
jmpcont1
plus:mov bx,1
cont1: ……
例2利用表實現(xiàn)分支。根據(jù)al中各位被置位情況,控制轉移到8個子程序p1~p8之一中去。轉移表的結構如表1所示。
分析:對于這種程序關鍵要找出每種情況的轉移地址,從圖中可見表地址=表基地址+偏移量, 而偏移量可由al各位所在位置*2求得。
表1 子程序r1—r8的入口地址表
p1
子程序r1的入口偏移地址
p2
子程序r2的入口偏移地址
p3
子程序r3的入口偏移地址
……
……
…….
……
p7
子程序r7的入口偏移地址
p8
子程序r8的入口偏移地址
datasegment
basedwsr0,sr1,sr2,sr3,
sr4,sr5,sr6,sr7
dataends
codesegment
assume cs:code,ds:data,es:data
begin:push ds
xor ax,ax
pushax
mov ax,data
mov ds,ax
lea bx,base ;表頭送bx
inal,port
getbit: rcr al,1;右移一位
jcgetad;移出位是1?
incbx
inc bx??;修改指針
jmpgetbi
getad: jmpword ptr[bx]??;實現(xiàn)散轉
codeends
endbegin
例3將內存中某一區(qū)域的原數(shù)據(jù)塊傳送到另一區(qū)域中。
分析:這種程序若源數(shù)據(jù)塊與目的數(shù)據(jù)塊之間地址沒有重疊,則可直接用傳送或串操作實現(xiàn);若地址重疊,則要先判斷源地址+數(shù)據(jù)塊長度是否小于目的地址,若是,則可按增量方式進行,否則要修改指針指向數(shù)據(jù)塊底部,采用減量方式傳送。程序如下:
datasegment
str db 1000dup(?)
str1equ str+7
str2equ str+25
strcount equ 50
dataends
stacksegment parastack‘stack’
stapndb100dup(?)
stackends
codesegment
assume cs:code,ds:data,es:data,ss:stack
goo proc
push ds
subax,ax
push ax
mov ax,data
mov ds,ax
mov es,ax
mov ax,stack
mov ss,ax
mov cx,strcount
mov si,str1
mov di,str2
cld
push si
add si,strcount-1
cmp si,di
popsi
jlok
std
add si,strcount-1
add di,strcount-1
ok:repmovsb
ret
gooendp
codeends
end goo
csegsegment
main procnear
assume cs:cseg, ds:data
start:
movax,dseg
movds,ax
exit:movax,4c00h
int21h
mainendp
csegends
endstart
例4 試根據(jù)al寄存器中哪一位為1(從低位到高位)把程序轉移到8個不同的程序分支中去。
branch_addressessegment; 定義數(shù)據(jù)段
branch_table dw routine_1
dw routine_2
dw routine_3
dw routine_4
dw routine_5
dw routine_6
dw routine_7
dw routine_8
branch_addressesends
procedure_selectsegment; 定義代碼段
main procfar; 定義主程序main
assume cs:procedure_select,ds:branch_addresses
start:
pushds
sub bx,bx
pushbx
mov bx,branch_addresses
mov ds,bx
; 程序的主要部分(寄存器相對尋址)
cmp al,0 ; (al)=0?
je continue ; (al)為0則轉到continue_main_line
mov si,0
l:shr al,1; 把al邏輯右移1位
jnc not_yet ; cf=0轉到not_yet
jmp branch_table[si] ; cf=1轉到相應程序分支
not_yet: add si,type branch_table; 修改地址add si,2
jmp l; 無條件跳到l
continue:; 其它程序段
…
routine_1:
… ; 程序段1
routine_2:
… ; 程序段2
ret
mainendp ; 主程序main結束
procedure_select ends
end start
用寄存器間接尋址方式實現(xiàn)跳躍表法的程序如下(僅給出修改后的程序的主要部分):
……
cmpal,0
je continue
leabx,branch_table ; branch_table的偏移地址送bx l: shral,1
jncnot_yet ; cf=0轉到not_yet
jmpword ptr[bx] ; cf=1轉到相應程序分支
not_yet: addbx,type branch_table ; 修改地址
jmpl; 無條件跳到l
continue:
……
用基址變址尋址方式實現(xiàn)跳躍表法的程序如下(僅給出修改后的程序的主要部分),與前兩種尋址方式的主要區(qū)別是這里使用了邏輯左移指令,即從al的高位向低位判斷,而前兩段程序是從al的低位向高位判斷。
……
cmpal,0
je continue
leabx,branch_table
movsi,7*type branch_table ; 14送si
movcx,8; 循環(huán)次數(shù)8送cx
l: shlal,1; 把al邏輯左移1位
jnbnot_yet ; cf=0轉到not_yet
jmpword ptr[bx][si]; cf=1轉到相應程序分支
not_yet: subsi,type branch_table; 修改地址
loop l; 循環(huán)
continue:
……
以上多個例子都是既有分支結構又有循環(huán)結構,實際上,多數(shù)程序都是各種程序結構的組合。而且,循環(huán)結構可以看作分支結構的一種特例,它只是多次走一個分支,只在滿足循環(huán)結束條件時,走另一個分支罷了。
算法和循環(huán)控制條件的選擇對程序的工作效率有很大的影響,而循環(huán)控制條件的選擇又是很靈活的,應該根據(jù)具體情況來確定??紤]算法時必須把可能出現(xiàn)的邊界情況考慮在內。
設置邏輯尺是循環(huán)控制中很常用的一種方法。除了靜態(tài)地預置外,還可以在程序中動態(tài)地修改標志位的值,以達到控制的目的。
循環(huán)可以有多層結構。多重循環(huán)程序設計的基本方法和單重循環(huán)程序設計是一致的,應分別考慮各重循環(huán)的控制條件及其程序實現(xiàn),相互之間不能混淆。另外,應該注意在每次通過外層循環(huán)再次進入內層循環(huán)時,初始條件必須重新設置。
起泡排序算法是多重循環(huán)程序設計中的一種常用方法。
分支程序結構可以有兩種形式。分別相當于高級語言中的if_then_else語句和case語句,適用于要求根據(jù)不同條件作不同處理的情況。
if_then_else語句可以引出兩個分支,case語句則可以引出多個分支,不論哪一種形式,它們的共同特點是:運行方向是向前的,在某一種特定條件下,只能執(zhí)行多個分支中的一個分支。
數(shù)組排序算法中可以采用折半查找法來提高查找效率。
case結構可以使用跳躍表法實現(xiàn),使程序能根據(jù)不同的條件轉移到多個程序分支中去。跳躍表法;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;是一種很有用的分支程序設計方法。