本次实验相对上一次实验来说难度稍大,主要是涉及了高级语言中没有手动维护的子程序参数传递。就如在学习笔记中提到的一样,通过变量传递和通过堆栈传递都涉及了堆栈的维护,需要在实践中仔细检查。
实验内容
(1)请编写一个子程序,在 STRING 开头的数据区中查找字符串 WE,数据区以$字符作为结束符。如查出,返回此字符所在的地址,若查不到,给’NOT FOUND’ 的提示。
注: 1) 结合题目要求,对于字符串 STRING 的初始化要考虑多种情况,从而得到 不同的输出。 2) 主程序和子程序采用变量传参的方式
(2) 一个班共有学生若干人,在内存中有一个按学号排列的期末总成绩表,编写 子程序实现按总成绩高低进行排序并将总成绩最高同学的学号输出(假定不 超过两位十进制数)。 1) 若有成绩相同的情况,则按照学号的先后排序。 2) 为了编程方便,可设计少数数据,满足题目要求即可。 3) 参数传递采用寄存器方式。 4) 需利用原有空间进行存储,排序算法任选。
(3) 下述代码段是计算 n! 子程序代码段采用了递归和嵌套结构,n 存放在 AL 中,n!存放在 BX 中。请 结合给出的部分代码完成程序,并绘制出程序调用示意图和堆栈变化示意图。
(4) 有 10 个字节的数据表 array,表内元素已按从小到大的顺序排列好。现给定 一元素 w,试编制子程序,实现在表内查找给定元素 w 的任务,若表内已有 此元素,则显示“Y”;否则,按顺序将此元素插入表中适当的位置。 1) 数据表需要自行进行初始化,数值或字符类型均可; 2) 主程序和子程序之间采用变量方式进行传参。 3) 若主程序和子程序采用堆栈方式进行传参,原始代码将如何修改?
对应程序
(1)注意题中的“考虑多种情况”,其中可能包括原字符串长度小于目标串的情况。当然,在下面的程序中,这种情况也是可以被正确处理的。
;使用变量传参
;打印下标
.MODEL SMALL
.DATA
STRING DB 'TWENTY$'
tar db 'WE'
ascii db 30h,31h,32h,33h,34h,35h,36h,37h,38h,39h
db 41h,42h,43h,44h,45h,46h
msg db 'NOT FOUND',13,10,'$'
.STACK
.CODE
.STARTUP
push ax
push si
push dx
push cx
xor ax,ax ;清空AX
xor si,si
xor dx,dx
mov bx,offset string
call findtar
pop cx
pop dx
pop si
pop ax
.EXIT
findtar proc
mov cx,lengthof string ;设置循环次数
mov si,0 ;设置目标串偏移
;暴力搜索
try:mov al,byte ptr[bx+si]
cmp al,tar[si]
jne clr
inc si ;若相等,递增si
cmp si,2
je break
jmp try ;继续比较下一个字符
clr:xor si,si ;不相等,SI置0
inc bx ;
loop try ;下标递增,循环
;循环完了未找到子串
mov ax,offset string-1 ;AX=-1
jmp finally
break:mov ax,bx
finally:
sub ax,offset string
cmp ax,-1
jne print
mov dx,offset msg
mov ah,9
int 21h
jmp endl
print:mov bx,offset ascii
mov dl,al
mov cl,4
shr dl,cl
mov si,dx
mov dl,byte ptr[bx+si]
push ax
mov ah,2
int 21h
pop ax
mov dl,al
and dl,0fh
mov si,dx
mov dl,[bx+si]
mov ah,2
int 21h
endl:ret
findtar endp
END
(2)选用冒泡排序算法。其中子程序内部的流程可以直接翻译高级语言。
.model small
.data
number dw 0001,0002,0003,0004,0005
score db 17,36,52,53,78
.stack
.code
;排序方法:冒泡排序
;传出参数:DX
;输出一位数字,表示学号
.startup
mov dx,lengthof number
call bubblesort
;下方是输出格式
mov dx,number
add dl,30h
mov ah,2
int 21h
mov dl,10
mov ah,2
int 21h
.exit 0
bubblesort proc
mov cx,dx
.repeat
mov si,0
mov bx,cx
dec bx
.repeat
mov al,score[si+1]
.if al>score[si]
mov dl,score[si]
mov score[si],al
mov al,dl
shl si,1
mov dx,number[si]
xchg number[si+2],dx
mov number[si],dx
shr si,1
.endif
inc si
.until si>=bx
.untilcxz
ret
bubblesort endp
end
(3)补充后的程序如下,原因已经在注释中说明:
.model small
.data
.code
.startup
main:mov ax,3 ;设n=3
call fact
xi: mov bx,dx
.exit 0
;阶乘子程序
;入口参数:AL中存放n
;出口参数:DX中存放n!
;所用寄存器: CX
fact proc
cmp al,0
jnz iia ;AL!=0,iia
mov dl,1 ;AL==0,DL=1
ret ;(1)
iia:push ax
dec al ;
call fact
x2:pop cx
call mult
x3: mov dx,ax
ret ;
fact endp
;无符号字节数乘法子程序
;入口参数:CL、DL中各为一乘数
;出口参数:AX中为乘积
mult proc
mov al,dl
mul cl
ret ;(3)
mult endp
end
假设fact(x)表示n=x时的fact子程序,mult(x)表示n=x的mult子程序,那么子程序调用顺序如下:
Main->fact(3)->fact(2)->fact(1)->fact(0)->fact(1)->mult(1)->fact(1)->fact(2)->mult(2)->fact(2)->fact(3)->mult(3)->fact(3)->main
(4)这是简单的线性表查找,可以直接翻译高级语言对应的操作。
.model small
.stack
.data
array db 2,4,6,8,10,12,14,16,18,20
target db 21
.code
.startup
pop ax
pop bx
pop cx
pop dx
pop si
call insert
pop si
pop dx
pop cx
pop bx
pop ax
.exit 0
;使用变量传参
insert proc
mov cx,lengthof array
mov dl,target
mov bx,offset array
mov si,0
.while si<cx
mov al,[bx+si]
.if al==dl ;找到对应元素,直接打印'Y'返回
mov dl,'Y'
mov ah,2
int 21h
mov dl,10
mov ah,2
int 21h
ret
.endif
.if al>dl ;元素大于target,直接插入
.while si<=cx
xchg dl,[bx+si]
inc si
.endw
ret
.endif
;当前元素小于target,查看下一个元素
inc si
.endw
.if si==cx ;若target大于所有数组中的数
mov [bx+si],dl ;将target放在末尾
ret
.endif
insert endp
end
总结
本次实验涉及的子程序都相对简单,完全可以先用高级语言(例如C)写一遍,再对照高级语言程序,结合汇编语言的高级语言特性,翻译成对应的汇编语言形式。反过来看,汇编语言的高级语言特性也极大地方便了我们书写较为复杂的汇编程序。