版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第4章教学重点综合应用第2章硬指令和第3章伪指令,第4章从程序结构角度展开程序设计,重点掌握:分支结构程序设计循环结构程序设计子程序结构程序设计4.1顺序程序设计顺序程序完全按指令书写的前后顺序执行每一条指令,是最基本、最常见的程序结构例4.1计算例4.2移位例题代码转换例4.2-1/2
.dataqvar dq1234567887654321h
.code moval,byteptrqvar[6] movbyteptrqvar[7],al moval,byteptrqvar[5] movbyteptrqvar[6],al moval,byteptrqvar[4] movbyteptrqvar[5],al moval,byteptrqvar[3] movbyteptrqvar[4],al图示例4.2-2/2 moval,byteptrqvar[2] movbyteptrqvar[3],al moval,byteptrqvar[1] movbyteptrqvar[2],al moval,byteptrqvar[0] movbyteptrqvar[1],al movbyteptrqvar[0],012
34
56
78
87
65
43
21h34
56
78
87
65
43
21
00h移位后图示第4章64位数据左移8位123456788765432100qvar[0]qvar[1]qvar[2]qvar[3]qvar[4]qvar[5]qvar[6]qvar[7]例题代码转换-1/2;查表法,实现一位16进制数转换为ASCII码显示 .modelsmall .stack .dataASCII db30h,31h,32h,33h,34h,35h db36h,37h,38h,39h ;0~9的ASCII码
db41h,42h,43h,44h,45h,46h ;A~F的ASCII码hex db0bh ;任意设定了一个待转换的一位16进制数4.2分支程序设计分支程序根据条件是真或假决定执行与否判断的条件是各种指令,如CMP、TEST等执行后形成的状态标志转移指令Jcc和JMP可以实现分支控制;还可以采用MASM6.x提供的条件控制伪指令实现单分支:求绝对值等双分支:例4.3等多分支:例4.4等例题求绝对值;计算AX的绝对值
cmpax,0
jnsnonneg ;分支条件:AX≥0
negax ;条件不满足,求补nonneg: movresult,ax ;条件满足;计算AX的绝对值
cmpax,0
jlyesneg ;分支条件:AX<0 jmpnonnegyesneg: negax ;条件不满足,求补nonneg: movresult,ax ;条件满足GoodBad双分支程序设计条件成立跳转执行第2个分支语句体,否则顺序执行第1个分支语句体。注意第1个分支体后一定要有一个JMP指令跳到第2个分支体后例题显示BX最高位-1 shlbx,1 ;BX最高位移入CF
jcone ;CF=1,即最高位为1,转移 movdl,’0’ ;CF=0,即最高位为0,DL←’0’
jmptwo
;一定要跳过另一个分支体one: movdl,’1’ ;DL←’1’two: movah,2 int21h ;显示例题显示BX最高位-2 shlbx,1 ;BX最高位移入CF
jncone ;CF=0,即最高位为0,转移 movdl,’1’ ;CF=1,即最高位为1,DL←’1’
jmptwo
;一定要跳过另一个分支体one: movdl,’0’
;DL←’0’two: movah,2 int21h ;显示例题显示BX最高位-3 movdl,’0’ ;DL←’0’ shlbx,1 ;BX最高位移入CF jnctwo ;CF=0,最高位为0,转移 movdl,’1’ ;CF=1,最高位为1,DL←’1’two: movah,2 int21h ;显示双分支程序可以改为单分支程序例4.3判断有无实根-1/2.startupmoval,_bimulalmovbx,ax ;BX中为b2moval,_aimul_cmovcx,4imulcx
;AX中为4ac(DX无有效数据) ;寄存器AL中是字母Y或y,则令AH=0;否则令AH=-1 cmpal,’Y’ ;AL是大写Y否?
jznext ;是,转移 cmpal,’y’ ;AL是小写y否?
jznext ;是,转移
movah,-1 ;不是Y或y,则AH=-1,结束
jmpdone
;一定要跳过另一个分支体next: movah,0 ;是Y或y,则AH=0,结束done: ...例题单分支和双分支多分支程序设计多个条件对应各自的分支语句体,哪个条件成立就转入相应分支体执行。多分支可以化解为双分支或单分支结构的组合,例如:orah,ah ;等效于cmpah,0
jzfunction0 ;ah=0,转向function0decah ;等效于cmpah,1
jzfunction1 ;ah=1,转向function1decah ;等效于cmpah,2
jzfunction2 ;ah=2,转向function2图示地址表形成多分支需要在数据段事先安排一个按顺序排列的转移地址表输入的数字作为偏移量。因为只有2个字节16位偏移地址,所以偏移量需要乘2关键是要理解间接寻址方式JMP指令地址表分支1地址分支2地址...table dwdisp1,disp2,disp3,disp4,... .datamsg db'Inputnumber(1~8):',0dh,0ah,'$'msg1 db'Chapter1:...',0dh,0ah,'$'msg2 db'Chapter2:...',0dh,0ah,'$‘ ...msg8 db'Chapter8:...',0dh,0ah,'$'table dwdisp1,disp2,disp3,disp4 dwdisp5,disp6,disp7,disp8 ;取得各个标号的偏移地址例4.4数据段-1/3此处等同于offsetdisp1
decax shlax,1 ;等效于addax,ax
movbx,ax
jmptable[bx];(段内)间接转移:IP←[table+bx]start2: movah,9 int21h .exit0disp1: movdx,offsetmsg1 ;处理程序1
jmpstart2 ...例4.4代码段-3/3可以改为calltable[bx]对应修改为rettable dwmsg1,msg2,...,msg9 ;地址表 ...
decax shlax,1
movbx,ax
movdx,table[bx] movah,9 int21h例4.4字符串地址表4.3循环程序设计循环结构一般是根据某一条件判断为真或假来确定是否重复执行循环体循环指令和转移指令可以实现循环控制;还可以采用MASM6.x提供的循环控制伪指令实现循环指令LOOPE:例4.6转移指令:例4.7多重循环:例4.8等循环指令LOOP:例4.5等 .modelsmall .stack .datasum dw? .code .startup xorax,ax ;被加数AX清0 movcx,100again: addax,cx
;从100,99,...,2,1倒序累加
loopagain movsum,ax ;将累加和送入指定单元 .exit0 end例4.5求和
计数控制循环循环次数固定;用二进制显示从键盘输入的一个字符的ASCII码
movah,1 ;从键盘输入一个字符
int21h
movbl,al ;BL←AL=字符的ASCII码;DOS功能会改变AL内容,故字符ASCII码存入BL
movah,2
movdl,':' ;显示一个分号,用于分隔
int21h习题4.12-1/2
movcx,8 ;CX←8(循环次数)again: shlbl,1 ;左移进CF,从高位开始显示
movdl,0 ;MOV指令不改变CF
adcdl,30h ;DL←0+30H+CF;CF若是0,则DL←'0';若是1,则DL←'1'
movah,2
int21h ;显示
loopagain
;CX减1,如果CX未减至0,则循环习题4.12-2/2
计数控制循环循环次数固定 .startup movax,wordX ;测试目标送AX movcx,16
;循环计数器置初值 movdl,-1 ;计位器置初值again: incdl testax,1 rorax,1 ;循环指令不影响ZF
loopeagain ;CX≠0且ZF=1(测试位为0),继续循环
jenotfound movbyteY,dl
jmpdonenotfound: movbyteY,-1 ;ZF=1,16个位均为0done: .exit0例4.6
计数控制循环最大循环次数固定,满足条件退出
movbx,offsetstringagain: moval,[bx] ;取一个字符 oral,al ;是否为结尾符0
jzdone ;是,退出循环 cmpal,'A' ;是否为大写A~Z
jbnext cmpal,'Z'
janext oral,20h
;是,转换为小写字母(使D5=1) mov[bx],al ;仍保存在原位置next: incbx
jmpagain ;继续循环done: .exit0例4.7大小写
条件控制循环利用标志退出大小写字母仅D5位不同冒泡法“冒泡法”是一种排序算法,不是最优的算法,但它易于理解和实现冒泡法从第一个元素开始,依次对相邻的两个元素进行比较,使前一个元素不大于后一个元素;将所有元素比较完之后,最大的元素排到了最后;然后,除掉最后一个元素之外的元素依上述方法再进行比较,得到次大的元素排在后面;如此重复,直至完成就实现元素从小到大的排序这需要一个双重循环程序结构图示冒泡法的排序过程序号数比较遍数123413228531641558321615885161583285158163285815163285第4章
mov
cx,count ;CX←数组元素个数
deccx ;元素个数减1为外循环次数outlp: mov
dx,cx ;DX←内循环次数
movbx,offsetarrayinlp:
moval,[bx] ;取前一个元素
cmpal,[bx+1] ;与后一个元素比较
jnanext ;前一个不大于后一个元素,则不进行交换
xchgal,[bx+1] ;否则,进行交换
mov[bx],alnext: incbx ;下一对元素
decdx
jnzinlp ;内循环尾
loopoutlp ;外循环尾例4.8计数控制双重循环;现有一个以$结尾的字符串,要求剔除其中的空格
.datastring db’Letushaveatry!’,’$’ .code .startup movsi,offsetstringoutlp: cmpbyteptr[di],’$’
;外循环,先判断后循环 jzdone ;为$结束 cmpbyteptr[si],’’
;检测是否是空格 jnznext ;不是空格继续循环例4.9剔除空格-1/2 movdi,si ;是空格,进入剔除空格分支 ;该分支是循环程序段inlp: incdi moval,[di] ;前移一个位置 mov[di-1],al
cmpbyteptr[di],’$’
;内循环,先循环后判断 jnzinlp
jmpoutlpnext: incsi ;继续对后续字符进行处理
jmpoutlpdone: .exit0 ;结束例4.9剔除空格-2/2条件控制双重循环4.3.4串操作类指令串操作指令是8086指令系统中比较独特的一类指令,采用比较特殊的数据串寻址方式,常用在操作主存连续区域的数据时主要熟悉: MOVSSTOSLODS CMPSSCASREP一般了解: REPZ/REPEREPNZ/REPNE串数据类型串操作指令的操作数是主存中连续存放的数据串(String)——即在连续的主存区域中,字节或字的序列串操作指令的操作对象是以字(W)为单位的字串,或是以字节(B)为单位的字节串串寻址方式源操作数用寄存器SI寻址,默认在数据段DS中,但允许段超越:DS:[SI]目的操作数用寄存器DI寻址,默认在附加段ES中,不允许段超越:ES:[DI]每执行一次串操作指令,SI和DI将自动修改:±1(对于字节串)或±2(对于字串)执行指令CLD后,DF=0,地址指针+1或2执行指令STD后,DF=1,地址指针-1或2串传送MOVS(movestring)把字节或字操作数从主存的源地址传送至目的地址MOVSB
;字节串传送:ES:[DI]←DS:[SI] ;SI←SI±1,DI←DI±1MOVSW
;字串传送:ES:[DI]←DS:[SI] ;SI←SI±2,DI←DI±2串存储STOS(storestring)把AL或AX数据传送至目的地址STOSB
;字节串存储:ES:[DI]←AL ;DI←DI±1STOSW
;字串存储:ES:[DI]←AX ;DI←DI±2串读取LODS(loadstring)把指定主存单元的数据传送给AL或AXLODSB
;字节串读取:AL←DS:[SI] ;SI←SI±1LODSW
;字串读取:AX←DS:[SI] ;SI←SI±2重复前缀指令(repeat)串操作指令执行一次,仅对数据串中的一个字节或字量进行操作。但是串操作指令前,都可以加一个重复前缀,实现串操作的重复执行。重复次数隐含在CX寄存器中重复前缀分2类,3条指令:配合不影响标志的MOVS、STOS(和LODS)指令的REP前缀配合影响标志的CMPS和SCAS指令的REPZ和REPNZ前缀REP重复前缀指令REP前缀可以理解为:当数据串没有结束(CX≠0),则继续传送REP
;每执行一次串指令,CX减1 ;直到CX=0,重复执行结束例4.10:字符串传送 movax,ds moves,ax ;设置附加段ES=DS
movsi,offsetsrcmsg movdi,offsetdstmsg movcx,lengthofsrcmsg
cld ;地址增量传送 repmovsb ;传送字符串
movah,9 ;显示字符串 movdx,offsetdstmsg int21h重复串传送(例4.10)
repmovsbagain: movsb ;传送一个字节
loopagain
;重复传送
movdx,cx ;字符串长度,转存DX
shrcx,1 ;长度除以2
repmovsw ;以字为单位重复传送
movcx,dx
andcx,01b ;求出剩余的字符串长度
repmovsb ;以字节为单位传送剩余字符字符串传送 xorsi,si ;SI指向首个字符 movcx,lengthofsrcmsg ;CX=长度again: moval,srcmsg[si] ;取源字符串的字符 movdstmsg[si],al ;传送到目的字符串 incsi ;指向下一个字符 loopagain ;重复传送不用串指令,需要使用循环结构不用串指令,没有寄存器限制例4.11:设置显示缓冲区 movdx,0b800h moves,dx movdi,0 ;设置ES:DI movcx,25*80 ;设置CX=填充个数 movax,0720h ;设置AX=填充内容
cld
repstosw重复串存储(例4.11) repstoswagain: stosw ;传送一个字
deccx ;传送次数减1
jnzagain
;判断传送次数cx是否为0again: moves:[di],ax ;传送一个字
adddi,2 ;指向下一个字
loopagain
;重复传送例4.12:取正负数-1
movsi,offsetblock movdi,offsetdplus movbx,offsetdminus
movax,ds moves,ax;数据都在一个段中,所以设置es=ds movcx,count ;cx←字节数 cld例4.12:取正负数-2go_on: lodsb
;从block取出一个数据 testal,80h ;检测符号位,判断是正是负 jnzminus ;符号位为1,是负数,转向minus
stosb ;符号位为0,是正数,存入dplus jmpagain ;程序转移到again处继续执行例4.12:取正负数-3minus: xchgbx,di
stosb
;把负数存入dminus xchgbx,diagain: deccx ;字节数减1 jnzgo_on ;完成正负数据分离串比较CMPS(comparestring)将主存中的源操作数减去至目的操作数,以便设置标志,进而比较两操作数之间的关系CMPSB
;字节串比较:DS:[SI]-ES:[DI] ;SI←SI±1,DI←DI±1CMPSW
;字串比较:DS:[SI]-ES:[DI] ;SI←SI±2,DI←DI±2串扫描SCAS(scanstring)将AL/AX减去至目的操作数,以便设置标志,进而比较AL/AX与操作数之间的关系SCASB
;字节串扫描:AL-ES:[DI] ;DI←DI±1SCASW
;字串扫描:AX-ES:[DI] ;DI←DI±2REPZ重复前缀指令REPZ/REPE前缀可以理解为:当数据串没有结束(CX≠0),并且串相等(ZF=1),则继续比较REPZ
;每执行一次串指令,CX减1 ;并判断ZF是否为0, ;只要CX=0或ZF=0,重复执行结束REPNZ重复前缀指令REPNZ/REPNE前缀可以理解为:当数据串没有结束(CX≠0),并且串不相等(ZF=0),则继续比较REPZ
;每执行一次串指令,CX减1 ;并判断ZF是否为1, ;只要CX=0或ZF=1,重复执行结束例4.13:比较字符串 movcx,lengthofstring1 movsi,offsetstring1 movdi,offsetstring2 cld
repzcmpsb ;重复比较两个字符 jnzunmat ;字符串不等,转移 movdl,’Y’ ;字符串相等,显示Y jmpoutputunmat: movdl,’N’ ;字符串不等,显示Noutput: ……解释重复比较的解释指令repzcmpsb结束重复执行的情况①ZF=0,即出现不相等的字符②CX=0,即比较完所有字符:这种情况下,如果ZF=0,说明最后一个字符不等;而ZF=1表示所有字符比较后都相等,也就是两个字符串相同所以,重复比较结束后,jnzunmat指令的条件成立ZF=0,字符串不相等第2章例4.13:比较字符串 ……again: cmpsb ;比较两个字符
jnzunmat
;有不同字符,转移
deccx jnzagain ;进行下一个字符比较 moval,’Y’ ;字符串相等 jmpoutputunmat: moval,’N’ ;字符串不等output: ……例4.14:查找字符串
movdi,offsetstring moval,‘‘ ;‘‘=
20h movcx,count cld
repnzscasb
;搜索 jzfound ;发现空格ZF=1,转移 ... ;不含空格,则继续执行found: ...例4.14:查找字符串
movdi,offsetstring moval,20h movcx,count cldagain: scasb
;搜索 jzfound ;发现空格ZF=1 deccx ;不是空格 jnzagain ;搜索下一个字符 ... ;不含空格,则继续执行found: ...4.4子程序设计把功能相对独立的程序段单独编写和调试,作为一个相对独立的模块供程序使用,就形成子程序子程序可以实现源程序的模块化,可简化源程序结构,可以提高编程效率子程序设计要利用过程定义伪指令参数传递是子程序设计的重点和难点子程序可以嵌套;一定条件下,还可以递归和重入4.4.1过程定义伪指令过程名 proc[near|far] ...过程名 endp过程名(子程序名)为符合语法的标识符NEAR属性(段内近调用)的过程只能被相同代码段的其他程序调用FAR属性(段间远调用)的过程可以被相同或不同代码段的程序调用对简化段定义格式,在微型、小型和紧凑存储模型下,过程的缺省属性为near;在中型、大型和巨型存储模型下,过程的缺省属性为far对完整段定义格式,过程的缺省属性为near用户可以在过程定义时用near或far改变缺省属性子程序的常见格式subname proc ;具有缺省属性的subname过程 pushax ;保护寄存器:顺序压入堆栈 pushbx ;ax/bx/cx仅是示例 pushcx … ;过程体 popcx ;恢复寄存器:逆序弹出堆栈 popbx popax
ret
;过程返回subname endp
;过程结束;子程序功能:实现光标回车换行dpcrlf proc
;过程开始
pushax
;保护寄存器AX和DX
pushdx movdl,0dh
;显示回车 movah,2 int21h movdl,0ah
;显示换行 movah,2 int21h
popdx
;恢复寄存器DX和AX
popax ret
;子程序返回dpcrlf endp
;过程结束无参数传递的子程序ALdisp proc
;实现al内容的显示
pushax
;过程中使用了AX、CX和DX
pushcx pushdx
pushax
;暂存ax movdl,al ;转换al的高4位 movcl,4 shrdl,cl ordl,30h ;al高4位变成3 cmpdl,39h jbealdisp1 adddl,7 ;是0Ah~0Fh,还要加上7aldisp1: movah,2 ;显示 int21h例4.15子程序-1/3
popdx
;恢复原ax值到dx anddl,0fh ;转换al的低4位 ordl,30h cmpdl,39h jbealdisp2 adddl,7aldisp2: movah,2 ;显示 int21h popdx popcx popax ret
;过程返回ALdisp endp例4.15子程序-2/3
... ;主程序,同例4.8源程序 movbx,offsetarray;调用程序段开始 movcx,countdisplp: moval,[bx]
callALdisp
;调用显示过程 movdl,',' ;显示一个逗号,分隔数据 movah,2 int21h incbx loopdisplp ;调用程序段结束 .exit0 ... ;过程定义 end例4.15主程序-3/3HTOASC proc;将AL低4位表达的一位16进制数转换为ASCII码 andal,0fh cmpal,9 jbehtoasc1 addal,37h ;是0AH~0FH,加37H
ret
;子程序返回htoasc1: addal,30h ;是0~9,加30H
ret
;子程序返回HTOASC endp具有多个出口的子程序4.4.2子程序的参数传递入口参数(输入参数):
主程序提供给子程序出口参数(输出参数):
子程序返回给主程序参数的形式:①数据本身(传值)②数据的地址(传址)传递的方法:①寄存器②变量③堆栈例4.16求校验和子程序计算数组元素的“校验和”校验和是指不记进位的累加入口参数: 数组的逻辑地址(传址) 元素个数(传值)出口参数: 求和结果(传值)把参数存于约定的寄存器中,可以传值,也可以传址。子程序对带有出口参数的寄存器不能保护和恢复(主程序视具体情况进行保护)子程序对带有入口参数的寄存器可以保护,也可以不保护;但最好一致例4.16a入口参数:CX=元素个数,DS:BX=数组的段地址:偏移地址出口参数:AL=校验和用寄存器传递参数
.startup ;设置入口参数(含有DS←数组的段地址) movbx,offsetarray
;BX←数组的偏移地址 movcx,count ;CX←数组的元素个数
callchecksuma
;调用求和过程 movresult,al ;处理出口参数 .exit0例4.16a主程序checksuma proc xoral,al ;累加器清0suma: addal,[bx] ;求和 incbx ;指向下一个字节
loopsuma retchecksuma endp end例4.16a子程序主程序和子程序直接采用同一个变量名共享同一个变量,实现参数的传递不通模块间共享时,需要声明例4.16b入口参数:count=元素个数,array=数组名(段地址:偏移地址)出口参数:result=校验和用变量传递参数
;主程序
callchecksumb ;子程序checksumb proc pushax pushbx pushcx xoral,al ;累加器清0 movbx,offset
array
;BX←数组的偏移地址 movcx,count
;CX←数组的元素个数例4.16b-1/2sumb: addal,[bx] ;求和 incbx loopsumb movresult,al ;保存校验和 popcx popbx popax retchecksumb endp例4.16b-2/2主程序将子程序的入口参数压入堆栈,子程序从堆栈中取出参数子程序将出口参数压入堆栈,主程序弹出堆栈取得它们例4.16c入口参数:顺序压入偏移地址和元素个数出口参数:AL=校验和用堆栈传递参数
.startup movax,offsetarray
pushax movax,count
pushax
callchecksumc
addsp,4 movresult,al .exit0例4.16c主程序图示要注意堆栈的分配情况,保证参数存取正确、子程序正确返回,并保持堆栈平衡checksumc proc
pushbp movbp,sp
;利用BP间接寻址存取参数 pushbx pushcx
movbx,[bp+6]
;SS:[BP+6]指向偏移地址
movcx,[bp+4]
;SS:[BP+4]指向元素个数 xoral,alsumc: addal,[bx] incbx loopsumc popcx popbx
popbp retchecksumc endp例4.16c子程序图示堆栈区及参数主程序实现平衡堆栈:addsp,n
子程序实现平衡堆栈:retn第4章子程序的嵌套子程序内包含有子程序的调用就是子程序嵌套没有什么特殊要求ALdisp proc
pushax
pushcx ;实现al内容的显示
pushax
;暂存ax
movcl,4 shral,cl
;转换al的高4位
callhtoasc
;子程序调用(嵌套)
popax
;转换al的低4位
callhtoasc
;子程序调用(嵌套) popcx popax retALdisp endp例4.15嵌套子程序-1/3;将AL低4位表达的一位16进制数转换为ASCII码HTOASC proc pushax pushbx pushdx movbx,offsetASCII;BX指向ASCII码表 andal,0fh ;取得一位16进制数
xlatASCII;换码:AL←CS:[BX+AL],注意数据在代码段CS例4.15嵌套子程序-2/3 movdl,al ;显示 movah,2 int21h popdx popbx popax
ret
;子程序返回
;子程序的数据区ASCII db30h,31h,32h,33h,34h,35h,36h,37h db38h,39h,41h,42h,43h,44h,45h,46hHTOASC endp例4.15嵌套子程序-3/3子程序的递归当子程序直接或间接地嵌套调用自身时称为递归调用,含有递归调用的子程序称为递归子程序递归子程序必须采用寄存器或堆栈传递参数,递归深度受堆栈空间的限制例4.12:求阶乘
.modelsmall .stack .dataN dw3result dw? .code .startup movbx,N
pushbx
;入口参数:N
callfact
;调用递归子程序
popresult
;出口参数:N! .exit0例4.17主程序-1/3图示;计算N!的近过程;入口参数:压入N ;出口参数:弹出N!fact proc pushax pushbp movbp,sp
movax,[bp+6]
;取入口参数N cmpax,0 jnefact1 ;N>0,N!=N×(N-1)!
incax
;N=0,N!=1 jmpfact2例4.17递归子程序-2/3图示fact1: decax ;N-1 pushax
callfact
;调用递归子程序求(N-1)! popax
mulwordptr[bp+6]
;求N×(N-1)!fact2: mov[bp+6],ax
;存入出口参数N! popbp popax retfact endp例4.17递归子程序-3/3图示递归子程序调用时进栈返回时出栈13!2!1!子程序的重入子程序的重入是指子程序被中断后又被中断服务程序所调用,能够重入的子程序称为可重入子程序。在子程序中,注意利用寄存器和堆栈传递参数和存放临时数据,而不要使用固定的存储单元(变量),就能够实现重入。子程序的重入不同于子程序的递归。重入是被动地进入,而递归是主动地进入;重入的调用间往往没有关系,而递归的调用间却是密切相关的。递归子程序也是可重入子程序。例题4.18:从键盘输入有符号十进制数子程序从键盘输入一个有符号十进制数;子程序还包含将ASCII码转换为二进制数的过程输入时,负数用“-”引导,正数直接输入或用“+”引导子程序用寄存器传递出口参数,主程序调用该子程序输入10个数据转换算法 .datacount =10array dwcountdup(0) ;预留数据存储空间 .code .startup movcx,count movbx,offsetarrayagain: callread
;调用子程序输入一个数据 mov[bx],ax
;将出口参数存放缓冲区 incbx incbx calldpcrlf;调用子程序,光标回车换行以便输入下一个数据 loopagain .exit0例题4.18-1/5;输入有符号10进制数的通用子程序;出口参数:AX=补码表示的二进制数值;说明:负数用“-”引导,正数用“+”引导或直接输入;数据范围是+32767~-32768read proc pushbx pushcx pushdx xorbx,bx ;BX保存结果 xorcx,cx
;CX为正负标志,0为正,-1为负 movah,1 ;输入一个字符 int21h例题4.18-2/5 cmpal,'+' ;是“+”,继续输入字符 jzread1 cmpal,'-' ;是“-”,设置-1标志 jnzread2
;非“+”和“-”,转read2
movcx,-1read1: movah,1 ;继续输入字符 int21hread2: cmpal,'0‘
;不是0~9之间的字符,则输入数据结束 jbread3 cmpal,'9' jaread3例题4.18-3/5转换算法 subal,30h;是0~9之间的字符,则转换为二进制数;利用移位指令,实现数值乘10:BX←BX×10 shlbx,1 movdx,bx shlbx,1 shlbx,1 addbx,dx ; movah,0
addbx,ax;已输入数值乘10后,与新输入数值相加 jmpread1 ;继续输入字符例题4.18-4/5转换算法read3: cmpcx,0 jzread4
negbx ;是负数,进行求补read4: movax,bx ;设置出口参数 popdx popcx popbx ret ;子程序返回read endp ;使光标回车换行的子程序dpcrlf proc ... ;省略dpcrlf endp end例题4.18-5/5ASCII码转换为二进制数①首先判断输入为正或负数,并用一个寄存器记录②接着输入0~9数字(ASCII码),并减30H转换为二进制数③然后将前面输入的数值乘10,并与刚输入的数字相加得到新的数值④重复②、③步,直到输入一个非数字字符结束⑤负数进行求补,转换成补码;否则直接保存数值本例采用16位寄存器表达数据,所以只能输入+327677~-32768间的数值但该算法适合更大范围的数据第4章例题4.19:显示有符号十进制数子程序在屏幕上显示一个有符号十进制数;子程序还包含将二进制数转换为ASCII码的过程显示时,负数用“-”引导,正数直接输出、没有前导字符子程序的入口参数用共享变量传递,主程序调用该子程序显示10个数据转换算法 .datacount =10array dw1234,-1234,0,1,-1,32767 dw-32768,5678,-5678,9000wtemp dw? ;共享变量 .code .startup movcx,count movbx,offsetarrayagain: movax,[bx] movwtemp,ax
;将入口参数存入共享变量
callwrite
;调用子程序显示一个数据 incbx incbx calldpcrlf ;便于显示下一个数据 loopagain .exit0例题4.19-1/5;显示有符号10进制数的通用子程序;入口参数:共享变量wtempwrite proc pushax pushbx pushdx
movax,wtemp
;取出显示数据 testax,ax ;判断零、正数或负数 jnzwrite1 movdl,'0' ;是零,显示“0”后退出 movah,2 int21h jmpwrite5例题4.19-2/5write1: jnswrite2 ;是负数,显示“-” movbx,ax ;AX数据暂存于BX movdl,'-' movah,2 int21h movax,bx
negax ;数据求补(求绝对值)write2: movbx,10 pushbx ;10压入堆栈,作为退出标志例题4.19-3/5转换算法write3: cmpax,0 ;数据(商)为零 jzwrite4 ;转向显示 subdx,dx ;扩展被除数DX.AX divbx ;数据除以10:DX.AX÷10 adddl,30h
;余数(0~9)转换为ASCII码
pushdx ;数据各位先低位后高位压入堆栈 jmpwrite3write4: popdx
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 幻灯片照相产品供应链分析
- β受体阻断药产品供应链分析
- 维生素泡腾片市场分析及投资价值研究报告
- 为残障人士提供服务行业市场调研分析报告
- 保险经纪服务行业市场调研分析报告
- 自行车脚踏车车轮项目运营指导方案
- 农业碳汇经济行业市场调研分析报告
- 云航空服务行业经营分析报告
- 团队协作培训-企业培训与咨询师
- 乐器背带产业链招商引资的调研报告
- DB13-T 5958-2024 金属非金属露天矿山采场边坡安全监测技术规范
- 医院康复科培训课件:《平衡功能评定及训练》
- 2024《整治形式主义为基层减负若干规定》全文课件
- 2025届高三数学一轮复习策略讲座
- 北京市八中2023-2024学年高二上学期期中生物试题 含解析
- 职能科室对医技科室医疗质量督查记录表(检验科、放射科、超声科、功能科、内镜室)
- 2024至2030年中国机器人行业市场竞争状况及发展趋向分析报告
- 国家义务教育质量监测科学复习试题及答案
- PCBA审核表实用模板
- 后进生转化课件
- 北京富力爱丁堡广场项目机电方案设计报告
评论
0/150
提交评论