汇编语言电话本管理课程设计.doc
一、软件背景介绍汇编语言是一种以处理器指令系统为基础的低级程序设计语言,采用助记符表达指令操作码,采用标识符表示指令操作数。它是一种面向机器,效率最高的程序设计语言。它具有很高的系统资源操作能力和较高的程序执行效率,非常适合与系统程序的设计。汇编语言可以开发出许多应用软件,利用汇编语言编写的程序的主要优点是可以直接、有效地控制计算机硬件,因而容易创建代码序列减小、运行快速的可执行程序,在某些应用领域汇编语言的作用是不容置疑和不可替代的。现在,通讯越来越发达,通讯录的存在成为必需。所以,应要求设计一个电话本,其功能如下:1.程序能够建立一个可存放30条以上记录的电话号码本;2.程序能够对记录进行查找、增加、删除、修改操作;3.录入字段包含姓名、电话、单位内容;4.通过姓名或电话查询记录并显示查询结果。程序运行后,显示一操作菜单,含录入、列示、查询和退出功能,用单字母进行功能选择。m 修改;d 删除;n插入; v 浏览;f - 查询;e 退出,返回DOS。录入操作能从键盘录入姓名、电话号码、工作单位的通讯录(不超过30人)存于内存数据区。列示功能能列出所有录入的资料。查询功能能按姓名查询通讯录,列出查找到的记录或给出未找到信息。 图1程序运行后的界面图图1中界面的实现是由图2的总流程图实现的。进入程序后,显示功能菜单:f - 查询;n 插入;m 修改;d 删除;v 浏览;e 退出,返回DOS。开 始显示菜单,选择功能f ?n ?m ?d ?v ?返回DOS调用modify,实现修改调用delete,实现删除调用disdata,显示数据调用select,实现查询调用adder,实现插入e ?YNNNNYNYYYY图2 总体程序流程图二、核心算法思想电话本系统程序应用字符串操作命令,实现了个人通讯信息的增加、删除、修改、查询。信息连续存储,设有计数器cnt总是保存最后一条记录的序号。插入时自动插入到最后一条记录后,同时cnt加1。删除时,用最后一条记录覆盖被删除的记录,cnt减1。每个字段均有自己的输入缓冲区和记录存储区。程序执行后,首先显示功能选择界面,根据提示,输入要完成功能的代号,进入相应的子程序。查询:显示选择菜单:1 按姓名查找;2 按电话查找。按姓名查找:输入查找内容到缓冲区,将其与记录姓名进行比较,相等输出,返回主程序。否则进行下一目录比较;按电话查找:输入查找电话到缓冲区,将其与记录电话进行比较,相等输出,返回主程序。否则进行下一目录比较。插入:检测cnt是否为30:是,电话本已满,拒绝插入,返回主程序;否,输入新的内容,将其插入到cnt后的存储单元中,cnt加1,清空缓存,以便用于下一次输入。提示添加成功。修改:调用slebyname ,检测cntselect是否为0:是,没有查到,返回;否,输入新内容到缓冲区,计算被修改内容的偏移量,送新内容,cntselect清零。删除:检测cnt是否为0:是,电话本为空,返回主菜单;否,调用slebyname ,检测cntselect是否为0:是,没有查到,返回;否,计算要删除数据的偏移量,用最后一条记录覆盖要删除的记录,cnt减1。显示:检测cnt是否为0:是,电话本为空,返回主菜单;否,显示第一条记录、姓名、电话、办公室。输入n 若没有显示完毕,显示下一跳,否则返回;p 若本记录为第一条,返回,否则输出前一条;e 退出。退出:返回DOS。信息录入:对于查询、删除、修改、以及插入,均需录入新内容以便进行字符匹配与增加,所以我们调用DOS功能中的0A号功能与01号功能,进行字符串与字符的输入。执行AH=01H号功能调用,从键盘读取一个字符,将该字符回显到屏幕上。主要用与菜单功能选择和对不定长字符串的录入。当输入回车时,加入“$”为字符串传送做准备。执行AH=0AH号功能调用,等待用户输入一个或多个字符,最后用回车确认。信息输出:当查到用户所需内容时,或用户输入数据超范围或成功输入时,都需要显示信息或提示。我们采用DOS功能调用中的09号与ROM-BIOS功能调用中的13号功能。执行AH=09H号功能调用,从当前光标开始显示DS:DX指向的以“$”为结尾的字符串。该调用也可以输出回车和换行字符产生回车和换行的作用。信息处理:当输入新内容后,若要完成查询、插入、删除、修改功能,还要调用字符串处理命令。传送利用MOVSB命令,比较应用CMPSB命令。MOVSB命令将数据段中的一个字节传送至附加段的主存单元。CMPSB命令用源数据串减去目的数据串,以比较两者之间的关系,配合REPE或REPNE使用。屏幕设置:INT 10H 是由 BIOS 对屏幕及显示器所提供的服务程序,可设置一个人性化的窗口。我们调用ROM-BIOS功能,使用6号功能使屏幕初始化或上卷,使用2号功能设定光标位置。三、核心算法流程图1、查询:显示选择菜单:1 按姓名查找;2 按电话查找。若输入的是1就调用按姓名查找函数。若输入的是2则调用按电话查找函数 开 始返 回 选择菜单 1 ? 2 ?调用selbytel调用selbynameYYNN图3 查询功能模块流程图2、插入:检测cnt是否为30:是,电话本已满,拒绝插入,返回主程序;否,输入新的内容,将其插入存储单元中,清空缓存,以便用于下一次输入。提示添加成功。开 始cnt=30?将新插入的记录插入到存储区计算目的地址的偏移量显示添加成功计数器加一,inc cnt输入新的记录内容将缓冲区清空返 回提示,电话本已满YN图4 插入子程序流程3、修改:调用slebyname ,检测cntselect是否为0:是,没有查到,返回;否,输入新内容到缓冲区,计算被修改内容的偏移量,送新内容,cntselect清零。cntselect=0?调用selbyname返 回开 始cntselect 清零把新内容拷入计算被修改内容的偏移量输入新内容到缓冲区提示没有记录YN图5 修改子程序流程图4、删除:检测cnt是否为0:是,电话本为空,返回主菜单;否,调用slebyname ,检测cntselect是否为0:是,没有查到,返回;否,计算要删除数据的偏移量,用最后一条记录覆盖要删除的记录,cnt减1。开 始提示,电话本为空cnt=0? N Y call slebyname,查询删除姓名提示,没有此记录cntselect=0? Y计算要删除记录的偏移量N计算最后一个数据的偏移量用最后一个记录,覆盖要删除的记录计数器cnt 减一,cntselect 清空返 回图6 删除子程序流程图四、源代码win macro opr1,opr2,opr3,opr4,opr5,opr6 ;建立窗口 pusha mov ah,06h mov al,opr1 mov bh,opr2 mov ch,opr3 mov cl,opr4 mov dh,opr5 mov dl,opr6 int 10h popa ;恢复原来寄存器数据 endmpos_curse macro op1,op2,op3 ;定义光标位置 pusha ;储存原来寄存器数据 mov ah,2 mov bh,op1 mov dh,op2 mov dl,op3 int 10h popa ;恢复原来寄存器数据endmprintf macro x,y,string;建立输出程序pushamov ax,seg string ; 将string所在段的段地址传给axmov es,axmov ah,13hmov al,2mov bh,0mov cx,(SIZEOF string)/2mov dh,xmov dl,ymov bp,OFFSET string ;将string所在的偏移地址传参给bpint 10hpopaendmprintf2 macro x,y,stringpushapos_curse 0,x,ymov ah,9hmov dx,OFFSET string ;将string所在的偏移地址传参给dxint 21hpopaendmstack segment stack;建立栈 dw 512 dup(?)stack endsdata segment viewstr db ' ',0e1h,'V',0e1h,'i',0e1h,'e',0e1h,'w',0e1h,'(',0e1h,'V',0e1h,')',0e1h,' ',0e1h ;菜单view findstr db ' ',0e1h,'F',0e1h,'i',0e1h,'n',0e1h,'d',0e1h,'(',0e1h,'F',0e1h,')',0e1h,' ',0e1h exitstr db ' ',0e1h,'E',0e1h,'x',0e1h,'i',0e1h,'t',0e1h,'(',0e1h,'E',0e1h,')',0e1h,' ',0e1h modifystr db ' ',0e1h,'M',0e1h,'o',0e1h,'d',0e1h,'i',0e1h,'f',0e1h,'y',0e1h,'(',0e1h,'M',0e1h,')',0e1h,' ',0e1h deletestr db ' ',0e1h,'D',0e1h,'e',0e1h,'l',0e1h,'e',0e1h,'t',0e1h,'e',0e1h,'(',0e1h,'D',0e1h,')',0e1h,' ',0e1h newstr db ' ',0e1h,'N',0e1h,'e',0e1h,'w',0e1h,'(',0e1h,'N',0e1h,')',0e1h,' ',0e1h nextstr db ' ',0e1h,'N',0e1h,'e',0e1h,'x',0e1h,'t',0e1h,'(',0e1h,'N',0e1h,')',0e1h,' ',0e1h prestr db ' ',0e1h,'P',0e1h,'r',0e1h,'e',0e1h,'v',0e1h,'(',0e1h,'P',0e1h,')',0e1h,' ',0e1h titlestr db 'Welcome to telephone directory!',0dh,0ah,'Enter your choice please!',0dh,0ah,'$' menustr db '1:Select',0dh,0ah,'2:Insert',0dh,0ah,'3:Modify',0dh,0ah,'4:Delete',0dh,0ah,'5:Show all record',0dh,0ah,'8:Esc',0dh,0ah,'$' enter1 db 0dh,0ah,'$' num db 'No.1$',15 dup(0),'No.2$',15 dup(0),'No.3$',15 dup(0),'No.4$',15 dup(0),'No.5$',15 dup(0) db 'No.6$',15 dup(0),'No.7$',15 dup(0),'No.8$',15 dup(0),'No.9$',15 dup(0),'No.10$',14 dup(0) db 'No.11$',14 dup(0),'No.12$',14 dup(0),'No.13$',14 dup(0),'No.14$',14 dup(0),'No.15$',14 dup(0) db'No.16$',14 dup(0),'No.17$',14 dup(0),'No.18$',14 dup(0),'No.19$',14 dup(0),'No.20$',14 dup(0) db'No.21$',14 dup(0),'No.22$',14 dup(0),'No.23$',14 dup(0),'No.24$',14 dup(0),'No.25$',14 dup(0) db'No.26$',14 dup(0),'No.27$',14 dup(0),'No.28$',14 dup(0),'No.29$',14 dup(0),'No.30$',14 dup(0) db'No.31$',14 dup(0),'No.32$',14 dup(0),'No.33$',14 dup(0),'No.34$',14 dup(0),'No.35$',14 dup(0) db'No.36$',14 dup(0),'No.37$',14 dup(0),'No.38$',14 dup(0),'No.39$',14 dup(0),'No.40$',14 dup(0) namelist db 40 dup(20 dup(0) ;存储40个姓名 telelist db 40 dup(20 dup(0) ;存储40个电话 unitlist db 40 dup(20 dup(0);存储40个单位名称 newname db 20 dup(0);插入用 newtele db 20 dup(0);插入用 newunit db 20 dup(0) cnt db 1 dup(0) cntselect db 1 dup(0) choice db 1 dup(0) disname db 'Name:$' ;将字符串“name:”放到disname中 distele db 'Tele:$'将字符串“tele:”放到distele中 disunit db 'Unit:$'将字符串“unit:”放到disunit中 backstr db 'Press any key to main menu!',0dh,0ah,'$' disstr db 'All record!',0dh,0ah,'$' selstr10 db 'Choose the way to select:$' selstr11 db '1:Select by name$' selstr12 db '2:Select by telephone',0dh,0ah,'$' selstr2 db 'The imformation!',0dh,0ah,'$' selstr3 db 'Name is not exist!',0dh,0ah,'$' selstr4 db 'Telephone is not exist!',0dh,0ah,'$' selstr5 db 'Telephone directory is empty!',0dh,0ah,'$' addstr1 db 'Input the new name and the new telephone number!',0dh,0ah,'$' addstr2 db 'Telephone directory is full!',0dh,0ah,'$' addstr3 db 'Add successfully!',0dh,0ah,'$' mass db ' $' modstr1 db 'Name:$' modstr2 db 'Phone:$' modstr3 db 'Input new record:',0dh,0ah,'$' modstr4 db 'Modified successfully!',0dh,0ah,'$' delstr1 db 'Telephone directory is empty!',0d,0ah,'$' delstr2 db 'Deleted successfully!',0dh,0ah,'$' disstr11 db 'No record!$' data endscode segment main proc far assume cs:code,ds:data;将代码段放入cs,将数据段放入ds mov ax,data mov ds,ax mov es,axmenu1: call displaytitle ;调用窗口排布函数 mov ah,01h int 21h cmp al,'f' ;将输入的al里的字母和f比较看是否相同 jz sel;与f相同则跳到sel指示的子程序去 cmp al,'n' ;将输入的al里的字母和n比较看是否相同 jz adde;与N相同则跳到adde指示的子程序去 cmp al,'m' ;将输入的al里的字母和m比较看是否相同 jz modi;与M相同则跳到modi指示的子程序去 cmp al,'d' ;将输入的al里的字母和d比较看是否相同 jz del;与D相同则跳到del指示的子程序去 cmp al,'v' ;将输入的al里的字母和V比较看是否相同 jz dis;与V相同则跳到dis指示的子程序去 cmp al,'e'将输入的al里的字母和E比较看是否相同 jz out1;与e相同 jmp menu1 sel:call select ;sel指示查询程序 jmp back ;跳回adde:call adder ;adde指示增加程序 jmp back;跳回modi:call modify ;modi指示修改程序 jmp back;跳回del: call delete ;del指示删除程序 jmp back;跳回dis:call disdata;dis指示罗列所有基本信息back:mov ah,01h int 21h jmp menu1 ;输入e,返回主菜单 jmp back;美化函数displaytitle proc near win 0,9eh,0,0,24d,79d ;定义窗口背景printf 6,68,viewstr;定义背景窗口的查询printf 9,68,findstr;定义背景窗口的查询printf 12,68,exitstr;定义背景窗口的退出printf 20,5,modifystr;定义背景窗口的修改printf 20,20,deletestr;定义背景窗口的删除printf 20,35,newstr;定义背景窗口的新建pos_curse 0,9,30 retdisplaytitle endp;窗口定义介绍disdata proc near ;浏览子程序 win 0,9eh,0,0,24d,79d;浏览子程序的背景 printf 6,68,nextstr;输出next(n) printf 10,68,prestr;输出pres(p) printf 14,68,exitstr;输出exit(e) lea si,cnt mov cl,si ;cl=cnt,从第一条开始输出,共输出cl条 mov bx,0;bx置0 cmp cl,0;cl置0 jz disdata2;跳到输出数据2disdata1:win 0,9eh,2,0,19d,67d;浏览子程序pos_curse 0,5,10lea dx,num ;找到电话排在第几位 add dx,bx;将bx中的数据与dx相加 mov ah,09h int 21h;sxn printf2 7,10h,disname lea dx,namelist ;找到姓名列表 add dx,bx;将bx中的数据与dx相加 mov ah,09h int 21h;sxn printf2 9,10h,distele lea dx,telelist ;找到电话列表 add dx,bx ;将bx中的数据与dx相加 mov ah,09h;123 int 21h printf2 11,10h,disunit;找到所在的 lea dx,unitlist add dx,bx ;将bx中的数据与dx相加 mov ah,09h int 21h;sxn disdata6: mov ah,01h int 21h cmp al,'n' ;next jnz disdata4 add bx,20 ;下条记录 mov al,cnt mov cl,20 mul cl cmp bx,ax jl disdata5 mov bx,0 jmp disdata1 ;跳到下条指令disdata4: cmp al,'p' ;检验AL寄存器内的值是不是pjnz disdata3sub bx,20cmp bx,0jnl disdata5mov bx,0disdata5: jmp disdata1disdata2: printf2 9h,14,disstr11retdisdata3: cmp al,'e' ;检验AL寄存器内的值是不是ejnz disdata6 retdisdata endpadder proc near win 0,9eh,2,0,19d,67d lea si,cnt ;判断电话簿是否已满,超过40不再插入 mov al,si cmp al,40 ;检验AL寄存器内的值是不是40 jb adder5 lea dx,addstr2 ;显示addstr2中的字符串 mov ah,09h int 21h jmp adder6adder5: printf2 05h,10h,addstr1 printf2 07h,10h,disname mov cl,19 lea si,newname ;将newname的偏移地址放到si中,使si指向newnameadder1: mov ah,01h int 21h cmp al,0dh je adder2 mov si,al inc si loop adder1adder2: mov al,24h mov si,al lea si,cnt ;计算目的地址的偏移量 mov bl,si xor ax,ax mov al,20 mul bl lea si,newname ;将newname的偏移地址放到si中,使si指向newname lea di,namelist ;将namelist的偏移地址放到的di中,使di指向namelist add di,ax mov cx,20 cld rep movsb;将新输入的名字插入namelist lea dx,enter1 mov ah,09h ;实现DOS调用中的09号功能 int 21h printf2 9h,10h,distele mov cl,19 lea si,newteleadder3:mov ah,01h ;实现DOS调用中的01号功能 int 21h cmp al,0dh ;检验AL寄存器内的值是不是0x0D je adder4 mov si,al inc si ;将si的内容自增 loop adder3adder4: mov al,24h mov si,al lea si,cnt;计算目的地址的偏移量 mov bl,si xor ax,ax mov al,20 mul bl lea si,newtele ;找到新电话的位置 lea di,telelist;找到电话列表的位置 add di,ax mov cx,20 cld rep movsb ;将新输入的电话号码插入telelist lea dx,enter1 mov ah,09h ;实现DOS调用中的09号功能 int 21h printf2 11,10h,disunit mov cl,19 lea si,newunit ;将newunit的偏移地址放到si中,使si指向newunitadder9: mov ah,01h int 21h cmp al,0dh je adder10 mov si,al inc si ;将si的内容自增 loop adder9adder10: mov al,24h mov si,al lea si,cnt;计算目的地址的偏移量 mov bl,si xor ax,ax mov al,20 mul bl lea si,newunit ;将newname的偏移地址放到si中,使si指向newname lea di,unitlist ;将unitlist 的偏移地址放到的di中,使di指向unitlist add di,ax mov cx,20 cld rep movsb lea dx,enter1 mov ah,09h int 21h lea si,cnt ;计数器加1:从当前第一位置插入记录 mov al,si inc al mov si,al win 0,9eh,2,0,19d,67d printf2 07h,15h,addstr3 lea si,newname ;找到新电话的位置 mov cx,20adder7: mov al,0 mov si,al inc si loop adder7;更新newname为0 lea si,newtele ;找到新电话的位置 mov cx,20adder8: mov al,0;将o放入AL中 mov si,al inc si loop adder8;更新newtele为0adder6: retadder endpselbyname proc near ;用名来找 win 0,9eh,2,0,19d,67d lea si,cnt mov al,si cmp al,0 ja selname6 printf2 06h,15h,selstr5;无记录 jmp selname5selname6:;有记录 printf2 06h,10h,disname lea si,newname ;找到姓名类表 mov cx,19selname1: mov ah,01h int 21h;输入姓名至newname cmp al,0dh je selname2 mov si,al inc si ;将si的内容自增 loop selname1selname2: mov al,24h mov si,al;在newname后加'$' lea dx,enter1 mov ah,09h int 21h lea si,cnt ;设置循环次数dx mov dx,si mov bx,0 selname3: lea si,newname lea di,namelist add di,bx mov cx,20 cld repe cmpsb;比较是否相等 pos_curse 0,08h,10h jz selname4 add bx,20;不相等 dec dx cmp dx,0 jnz selname3 printf2 09h,14,selstr3 jmp selname5selname4: lea dx,distele mov ah,09h ;实现DOS调用中的09号功能 int 21h lea dx,telelist ;将telelist的偏移地址放到的di中,使di指向telelist add dx,bx ;将bx中的数据与dx相加 mov ah,09h int 21h lea dx,enter1 mov ah,09h int 21h pos_curse 0,10,10h ;输出单位 lea dx,disunit mov ah,09h int 21h lea dx,unitlist add dx,bx ;将bx中的数据与dx相加 mov ah,09h int 21h lea dx,enter1 mov ah,09h int 21h mov ax,bx ;计算器记录查询到的是第几个 mov bl,20 div bl inc al lea si,cntselect ;将cntselect 的偏移地址放到的si中,使si指向cntselect mov si,al selname5: lea si,newname ;找到新电话的位置 mov cx,20selname7: mov al,0 ;将newname全部更新为0,以便下一次查找或插入 mov si,al inc si loop selname7 retselbyname endpselbytele proc near ;用号码来找 win 0,9eh,2,0,19d,67d lea si,cnt mov al,si cmp al,0 ja seltele6 printf2 06h,15h,selstr5 jmp seltele5seltele6: printf2 06h,10h,distele lea si,newtele ;将newtele 的偏移地址放到的si中,使si指向newtele mov cx,19seltele1: mov ah,01h ;实现DOS调用中的01号功能 int 21h cmp al,0dh je seltele2 mov si,al inc si ;将si的内容自增 loop seltele1seltele2: mov al,24h mov si,al lea dx,enter1 mov ah,09h int 21h lea si,cnt ;设置循环次数 mov dx,si mov bx,0 seltele3: lea si,newtele lea di,telelist add di,bx ;将bx中的数据与di相加 mov cx,20 cld repe cmpsb pos_curse 0,08h,10