📄 phones.asm
字号:
data_seg segment
namcount dw 0
tel_tab db 50 dup(28 dup(' '))
nameitem label byte
nmax db 21
ncurlen db ?
namefld db 21 dup(?)
phoneitem label byte
pmax db 9
pcurlen db ?
phonefld db 9 dup(?)
addend dw ?
namtemp db 28 dup(?),13,10,'$'
swap db 0
msg_count db 'How many records do you want to input?',13,10,'$'
msg_illcount db 'Error:The number of your enter exceed the limit of 50! Plesae input the number again!',13,10,'$'
msg_illch db 'Error:The number of your enter is illegal! Please intput the number again!',13,10,'$'
msg_inputnam db 'Input name:','$'
msg_inputerr db 'Error:Input error!,please input a name!',13,10,'$'
msg_inputnum db 'Input a telephone number:','$'
msg_inquire db 'Want to find a telephone number?(Y/N)','$'
msg_sname db 'name?',13,10,'$'
msg_outtitle db 'name tel.',13,10,'$'
msg_nomatch db 'No such name!Insert again(Y/N)?',13,10,'$'
msg_result db 'Phone list:',13,10,'$'
bbb db '***********************************','$'
list db 'names tel',13,10,'$'
data_seg ends
stack_seg segment para stack 'stack' ;定义堆栈段
dw 256 dup(0)
stack_seg ends
code_seg segment
assume cs:code_seg,ds:data_seg,es:data_seg,ss:stack_seg
main proc far
start:
mov ax,data_seg
mov ds,ax ;初始化数据段
mov es,ax ;初始化附加段
cld ;df=0
lea di,tel_tab ;名字表的首地址放入di
lea dx,msg_count
mov ah,9
int 21h ;显示信息0:'How many names do you want to enter?'
again:
call decibin ;调用decibin(将输入的十进制次数转换成机器能识别的二进制数)
cmp dx,2 ;注意该条语句和下面的跳转语句的位置.计数器(记录名字数的位数)
call crlf ;回车换行
je exit1 ;一个有效字符都没输入,跳转要求重新输入.输入的为非法字符即非数字则不等输入完就跳出
push bx
cmp bx,50 ;
ja return ;输入的个数大于50出错跳出
;输入表中项数并保存在bx中
repeat:
pop bx
cmp namcount,bx ;目前项数和要求输入的项数比较,名字数和bx比较
je choice ;如果所有项都输入完毕则跳到choice排序
push bx ;stor_name会用到bx,先保存
lea dx,msg_inputnam
mov ah,9
int 21h ;要求输入名字
call input_name ;调用input_name
cmp ncurlen,0 ;没有输入了则开始排序,输入名字的字符数为0跳转
je choice
call stor_name
call input_phone ;调用input_phone
jmp repeat ;由于tel_tab是顺序连续存储,每一次输入一项后,di即指向下一项的开始,所以无需调整
choice:
cmp namcount,1
jb return1 ;表中项数小于1则要求输入
call name_sort ;不小于调用name_sort
rotate:
lea dx,msg_inquire ;输出'Do you want to find a telephone number?(Y/N)'
mov ah,9
int 21h ;显示是否查找电话号码
mov ah,1
int 21h ;由键盘输入‘Y’或‘N’
cmp al,'y'
je loop0
cmp al,'Y'
jne exit ;不为‘Y'或'y'跳出转至exit
jmp loop0 ; 为‘Y'回车、换行
loop0:
call crlf
lea dx,msg_sname ;'name?'
mov ah,9
int 21h ;显示要查询电话的姓名
call input_name ;输入姓名
call name_search ;调用name_search
jmp rotate ;返回查找另一个电话
insert:
call crlf
call stor_name
;call printline
call input_phone ;cmp namcount,1
;jb return1 ;表中项数小于1则要求输入
call name_sort ;不小于调用name_sort
call printline
jmp rotate
exit1:
lea dx,msg_illch ;输入错误的数字,要重新输入
mov ah,9 ;'Error:The number of your enter is not allowed! Please intput the number again!'
int 21h
jmp again
return: ;超过了50
lea dx,msg_illcount ;'Error:The number of your enter exceed the limit of 50! Plesae input the number again!'
mov ah,9
int 21h
jmp again
return1:
lea dx,msg_inputerr ;输出'Error:Input error!,please input a name!'
mov ah,9
int 21h ;没有输入名字
jmp repeat ;出错跳转
exit:
call printline ;输出排序结果
;输入任意字符退出
mov ah,7
int 21h
mov ax,4c00h
int 21h
main endp ;主程序结束
name_search proc near ;在表中顺序查找输入的名字
lea di,tel_tab ;把输入的名字首地址放入di
push di ;保存名字表首址,di为指向tel_tab表项的指针
mov bx,namcount ;名字的个数放bx
loop1:
lea si,namefld ;名字的缓存区首地址放入si
mov cx,20
repe cmpsb ;连续查找匹配名字
je found ;找到跳转found
pop di ;没找到di出栈
add di,28 ;把查找转到下一个名字
push di
dec bx
jnz loop1 ;循环查找
lea dx,msg_nomatch
mov ah,9
int 21h ;一直没找到则显示没有找到名字
mov ah,1
int 21h ;由键盘输入‘Y’或‘N’
cmp al, 'y'
je insert
;cmp al,'Y' ;此时di应指向插入位置
jne loop0 ;不为‘Y'或'y'跳转至重新输入名字查找
;jmp insert
found:
pop di
lea dx,msg_outtitle
mov ah,9
int 21h
mov si,di ;把要找到的内容暂存在namtemp中
lea di,namtemp
mov cx,28
rep movsb
lea dx,namtemp
mov ah,9
int 21h ;显示查到的姓名和电话号码
ret
name_search endp
decibin proc near ;键盘输入十进制数转换成二进制数
mov bx,0 ;bx清零
mov dx,2 ;输入数的位数置2
newchar:
mov ah,1
int 21h ;一号功能调用(输入字符并回显)
sub al,30h
jb exit2 ;非数字退出
cmp al,9
ja exit2 ;大于9退出(十进位制数每位0-9)
cbw ;字节转换成字(al->ax)
xchg ax,bx ;交换ax、bx
mov cx,10
push dx
mul cx ;先保存,dx×10
xchg ax,bx ;再将ax、bx交换回
add bx,ax
pop dx
dec dx
jnz newchar ;位数不为0跳转
exit2: ret
decibin endp ;结束
input_name proc near ;子程序(输入名字)
lea dx,nameitem
mov ah,0ah
int 21h ;输入名字并送入缓存区
call crlf ;回车、换行
mov bh,0
mov bl,ncurlen ;把名字的字符个数放入bx低位
mov cx,21 ;置循环次数
sub cx,bx
repeat1:mov namefld[bx],20h
inc bx
loop repeat1 ;输入的名字为20字节,不足的用空格补足
ret
input_name endp
stor_name proc near ;子程序(传送名字的每个字母到si)
;需要事先已设置好di
inc namcount
cld ;df=0(从小到大)
lea si,namefld
mov cx,20
rep movsb ;重复传送串名字(以字节为单位),直至送满20即cx=0 ,di指向tel_tab
ret
stor_name endp
input_phone proc near ;子程序(输入电话号码)
;需要事先已设置好di
lea dx,msg_inputnum
mov ah,9
int 21h ;显示要求输入电话号码
lea dx,phoneitem
mov ah,10
int 21h ;输入电话号码并送入缓存区
mov bh,0
mov bl,pcurlen
mov cx,9 ;置循环次数
sub cx,bx
repeat2:mov phonefld[bx],20h
inc bx
loop repeat2 ;输入的电话为8字节,不足的用空格补足
call crlf
cld ;df=0
lea si,phonefld
mov cx,8
rep movsb ;把输入的号码存入namtab表中,重复传送串电话号码(以字节为单位)
ret
input_phone endp
name_sort proc near ;子程序 ;有交换标志的冒泡排序,需要设置di
push di
push ax
push bx
cmp namcount,1
jz exit4 ;比较名字个数(只有一个名字即退出)
s1:
mov swap,0
sub di,56 ;di指针后移两个表项,第一次指向倒数第二项,以后每跑一趟前移一项
mov addend,di ;重新计算表尾指针
lea si,tel_tab
s2:
mov cx,20 ;置循环计数值
mov di,si
add di,28 ;di->后项,si->前项
mov ax,di ;后项保存在ax
mov bx,si ;前项保存在bx
repe cmpsb ;源-目标,即前项如果大于后项,交换;
jbe s3
call exchange
s3:
mov si,ax
cmp si,addend
jbe s2 ;是否已到namtab表尾,如果没到继续循环
cmp swap,0 ;如果有交换,继续下一趟
jnz s1
exit4:
pop bx
pop ax
pop di
ret
name_sort endp
exchange proc near ;交换tel_tab中di,si所指表项的内容,前项保存在bx
mov cx,28
lea di,namtemp
mov si,bx
rep movsb
mov cx,28
mov di,bx
rep movsb
mov cx,28
lea si,namtemp
rep movsb
mov swap,1
ret
exchange endp
printline proc near ;输出排序结果,不需要设置di,会改变di值
push di
push namcount ;printline 会被多次调用,保存namcount的值
call crlf ;回车、换行
lea dx,msg_result ;'The result of sort is as follows:'
mov ah,9
int 21h
;显示升序输出姓名、电话
lea dx,list
mov ah,9
int 21h
lea dx,bbb
mov ah,9
int 21h
call crlf
call crlf
lea si,tel_tab
loop2:
lea di,namtemp
mov cx,28 ;si每一次loop2会自动修正
rep movsb ;循环传送姓名、电话至输满27字节即cx=0
lea dx,namtemp
mov ah,9
int 21h ;显示姓名、电话
dec namcount ;名字数减1
jnz loop2 ;没输完则循环输出
pop namcount
pop di
ret
printline endp
deciasc proc near ;把10进制数转换成相应的ASCII码,digit in bl
mov ch,10d
mov cl,10d
re: ;判断退出条件
cmp ch,0
je quit
;取每一10进制位上的数字
mov al,bl;
cbw
div ch;
mov bl,ah ;余数继续除相应权,取相应位的10进制数字
call printit
mov al,ch
cbw
div cl
mov ch,al
jmp re
quit:
ret
deciasc endp
printit proc near
;输出1位数字对应的ASCII码,binary number in al
add al,30h
mov dl,al
mov ah,2
int 21h
ret ;ret不能少!
printit endp
crlf proc near
;输出回车换行
mov dl,0dh ;mov指令不影响标志位
mov ah,2
int 21h
mov dl,0ah
mov ah,2
int 21h
ret
crlf endp
code_seg ends
end start
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -