收藏 分销(赏)

数字计算器的汇编语言实现.docx

上传人:可**** 文档编号:4315542 上传时间:2024-09-05 格式:DOCX 页数:9 大小:359.73KB
下载 相关 举报
数字计算器的汇编语言实现.docx_第1页
第1页 / 共9页
数字计算器的汇编语言实现.docx_第2页
第2页 / 共9页
点击查看更多>>
资源描述
1 项目特点及目的 本课程设计是一次程序设计方法及技能的基本训练,通过实际程序的开发及调试,巩固课堂上学到的关于程序设计的基本知识和基本方法,进一步熟悉汇编语言的结构特点和使用,达到能独立阅读、设计编写和调试具有一定规模的汇编程序的水平。 2 题目简介 用8086汇编语言编写一个能实现四则混合运算、带括号功能的整数计算器程序。程序能实现键盘十进制运算表达式的输入和显示(例如输入:“1+2*(3-4)”),按“=”后输出十进制表示的运算结果。 3 程序设计要求 u 遵循模块化、结构化的编程思路 u 程序必须正确运行 u 程序简明易懂,多标明注释,具有良好的程序书写风格 u 适当优化程序,提高程序的运行效率 4 工作条件 使用的设备及软件为8086兼容机及MASM汇编开发软件。 5题目分析 根据题目要求,可以把程序的工作过程划分为运算表达式输入、计算、结果输出三部分。因此在编写程序时可以按此把程序大致划分为三个模块。 5.1 运算表达式输入 用户通过键盘输入的运算表达式为一个ASCII码字符串,字符串的最后一个字符是“=”号。对于这个运算表达式,“+、-、*、/、(、)、0~9、=”是合法的表达式内容,其他的字符则是无法进行运算的非法内容,因此需要首先进行表达式合法性检查。另外,由于计算机能进行计算的是2进制的补码,因此还需要把以ASCII码表示的数值转换为补码的形式并加以保存。当然,控制运算方式的符号也要进行保存。因此,“运算表达式输入”这个模块可以细化为:表达式合法性检查、数值的ASCII码到补码转换及保存、符号的保存三个小部分,如图6-1所示。 图6-1 “运算表达式输入”的流程图 运算表达式合法性的检查方法 观察“ASCII字符编码表”,可以发现“+、-、*、/、(、)”的ASCII码由28H到2FH,而“0~9”的ASCII码则由30H到39H,因此只需对输入的字符一个一个地进行数值范围比较,看看是否处于28H~39H这个范围里面,即可区分输入的表达式是否合法,流程图如图6-2所示。此流程图是采用循环输入字符的方法,每输入一个字符即进行判断。读者也可以采用输入字符串的方法,把整个运算表达式接收完毕后再进行判断。 图6-2 运算表达式合法性检查流程图一 另一方面,对于含有括号的运算表达式,当左括号的数量与右括号数量不相等时,表达式也是非法的。因此,可以设置一个起始值为0的变量(下面称其为配对标志),当输入“(”时此变量加一,当输入“)”时减一,则当表达式输入结束时,只需判定此配对标志是否为0,即可判定左右括号数量是否相等。 图6-3运算表达式合法性检查流程图二 数值的补码转换方法 要进行数值的ASCII码到补码的转换,首先就得判断输入的字符是数值还是符号。根据上文所提,“+、-、*、/、(、)”的ASCII码由28H到2FH,而“0~9”的ASCII码则由30H到39H,只需比较字符是否小于等于2FH(或小于30H)即可判断是否为符号,否则则是数值,如图6-2所示。 众所周知,要把一个ASCII码数值转换为二进制补码的形式,只需要对其减30H即可实现。但如果输入的是多位数,例如123,那么计算机获得的是31H、32H、33H三个字节,即使分别对这三个字节进行减30H操作,也只是获得1、2、3三个数而已。实际上可以利用加权的方法合并这几个数: 123=1×100+2×10+3×1 但另一个问题是,由于输入是随机的,即输入的运算数有多少位是未知的,因此无法使用上面的方面静态确定每一位的权重。这里介绍的方法是,每输入运算数的一位,则把前面的合并结果(称为原值)乘以10再与这一位相加,实现动态的加权合并。例如: 令原值为0,输入1,结果为:0×10+1=1 输入2,结果为:1×10+2=12 输入3,结果为:12×10+3=123 即:123=(((0×10+1)×10+2)×10)+3。数值的补码转换流程如图6-4所示,当然,在获得第一个数值输入前要先把原值设置为0。 图6-4 数值的补码转换流程图 由于符号全部是一个字节,无需进行任何转换即可保存,处理简单,这里不作探讨。 5.2 计算 由于运算表达式有多个数值和符号,而符号有不同的优先级别,因此上文提到的数值保存和符号保存应该分开两个地方进行保存,这样有利于表达式的计算算法设计。下面把“+、-、*、/”称为运算符,把“(、)”称为优先符。 图6-5 运算表达式的存储举例 观察图6-5的三条运算表达式,再联系四则混合运算的优先原则,可以归纳出几点: (a) 数值的数量是运算符的数量加1(优先符不算),第1个运算符代表第1、2个数值的运算操作,第N个运算符代表第N、N+1个数值的运算操作…… (b) 每进行一次运算,相应的运算符即被消除,而参与运算的两个数值合并为一个数值,仍然满足(a)。例如图6-5(a),当完成乘法运算后,数值存储区有408、56两个数,符号存储区有“+”一个运算符。 (c) 括号(优先符)的作用是把括号内的运算符的优先级别提高到比外部高。 因此,要实现运算表达式的运算,最重要的就是确定所有运算符的优先级别。下面讨论运算符优先级别的编程设计方法。 运算优先级别的静态确定法 此方法是完成了把整条运算表达式全部存入数值存储区和符号存储区后才开始对运算符优先级进行判断的方法: n 设置“*、/”的优先级为2、“+、-”的优先级为1; n 括号内部的所有运算符的优先级全部加2。 运用优先级别静态确定法处理图6-5的三条表达式的运算符,结果如图6-6所示。其中图6-6(c)的“34+56-8”由于被括号括起两次,因此其两个运算符“+、-”的优先级别均加了两次2。 图6-6 运算符的静态优先级别 最后,由于四则混合运算遵循从左往右计算的原则,即相同优先级别的运算符靠左的优先。因此,只需计算出符号存储区里面的所有运算符的优先级别,然后根据优先级的大小先后执行运算符对应的运算即可实现计算(当然每进行一次运算,相应的运算符即被消除,而参与运算的两个数值合并为一个数值)。当数值存储区里面剩下一个数值时,运算结束,这个最后的数值就是运算的最终结果。 读者请自行设计此算法的流程图。 运算优先级别的动态确定法 运算优先级别静态确定法具有容易理解、实现简单的优点,而其缺点是:如果运算表达式太长、太多数值和符号时,则会占用较多的存储空间,而且计算优先级的工作量也会增多。动态确定法是在运算表达式未结束输入即开始计算的一种方法。由于在表达式输入阶段已开始计算,因此计算结果的速度比静态确定法快。 观察图6-5(a),当用户输入“+”时,已经可以开始计算“12*34”;观察图6-5(b),当用户输入“-”时,已经可以开始计算“34+56”;观察图6-5(c),当用户输入第一个“-”时,已经可以开始计算“12*21”。也就是说,当用户输入的运算符的优先级不大于前一个运算符时,即可开始前一个运算符的计算。 问题是,对于有括号的运算表达式,在用户没有完成运算表达式的全部输入前,很难提前确定括号内部运算符的优先级。为了解决这个问题,动态确定法把优先符(括号)也赋予了优先级: n “(”,优先级为5; n “*、/”,优先级为4; n “+、-”,优先级为3; n “)”,优先级为1。 计算图6-5三条运算表达式的所有符号的优先级别,结果如图6-7所示。 图6-7运算符的动态优先级别 设计计算的条件: (1) 只有优先级为3、4的符号(即+、-、*、/)可以进行计算; (2) 如果某符号的优先级大于等于下一个的优先级时,对此符号进行相应运算(当然每进行一次运算,相应的运算符即被消除,而参与运算的两个数值合并为一个数值); (3) 如果左右括号相邻,且左括号在右括号左边时(即在符号存储区里面出现“()”的情况,或者在优先级队列里出现“51”的情况),把这对括号消除掉。 最后,当数值存储区里面剩下一个数值(或者符号存储区里面没有符号)时,运算结束,这个最后的数值就是运算的最终结果。读者请自行设计此算法的流程图。 5.3 结果输出 当数值存储区里面剩下一个数值(或者符号存储区里面没有符号)时,运算结束,需要把运算结果输出显示。 分析运算结果的特点:运算结果为一个2进制补码,整数,如果数据长度为16位,则运算结果范围是:-32768~32767。运算结果的输出要解决的主要问题是:正负数区分、补码到ASCII码转换并输出显示。运算结果的输出流程如图6-8所示。 图6-8 结果输出流程图 正负数区分 运算结果有三种情况:正整数、负整数、零。运算结果以补码形式对这三种情况进行统一的存储,但显示输出时则有所不同。负整数前面需要显示“-”号,因此需要对运算结果的符号进行判断。另一方面,正整数和零的补码与原码相同,而负整数的补码则不一样。把负整数进行取补码运算,把它转换为原码,可以实现运算结果统一的ASCII码转换输出方法,而不需要分别为正整数和零、负整数分别设计两个不同的ASCII码转换程序,如图6-9所示。 图6-9 正负数区分流程图 补码到ASCII码转换 计算结果在屏幕上的输出显示实际上是ASCII码的输出显示。假设程序采用的数据长度为16位,则运算结果范围是:-32768~32767,即屏幕最多得显示5位ASCII码。由于上文已经把结果统一为原码,下面介绍如何把原码转换为ASCII码。 这个转换过程实际上跟上文的“数值的补码转换方法”是相反操作。例如要把123在屏幕上输出显示,即要把123的百位、十位、个位分离,得到1、2、3,然后转换为31H、32H、33H三个ASCII码。众所周知,把一位数转换为ASCII码只需加30H即可,下面介绍把一个多位数的各位分离的方法。 (一)除十法 分离方法是:对一个多位数进行除10处理,得到的余数即为个位数,而商则是删除个位后的多位数。对商反复进行除10处理,直到商为0为止,即可把各位数分离。例如对123进行除十法处理: 123/10,商是12,余数是3 12/10,商是1,余数是2 1/10,商是0,余数是1 可见经过三次除十计算,得到的三个余数刚好就是对123的各位的分离结果。接着只需分别对这些余数加30H即可转换为ASCII码,实现输出转换。 除十法的优点是不需要理会要输出的数值有多少位,不断除以10直到商为0即可;缺点是得到的余数的顺序跟输出的方向相反,不方便输出。例如上例得到的三个余数的顺序是3、2、1,加30H转换输出后屏幕显示为“321”,跟期望显示的顺序相反,要作进一步处理。处理方法是把余数放进堆栈里面,然后再出栈显示。由于堆栈是先进后出的,即可解决该输出的顺序问题。 图6-10 除十法流程图 (二)除最高位法 分离方法是先除以10位数-1,得到的商即为最高位,余数为删除最高位后的多位数。接着令余数除以10位数-2,得到的商为次高位,……。例如123,其位数是3(个位、十位、百位),则计算过程为: 123/103-1,商是1,余数是23 23/103-2,商是2,余数是3 3/103-3,商是3,余数是0 可见经过三次计算,得到的三个商刚好是对123的各位的分离结果,而且顺序跟输出方向相同。可以直接加30H转换输出,屏幕显示为“123”。 该方法的缺点是:必须首先确定要输出的数值有多少位,编程者必须十分清楚需要输出的数值的数值范围。 图6-11 除最高位法流程图 源程序代码(与上面讲解的方法有点出入) ;------数据段------------- DATA SEGMENT TAB1 DB 13,10,"HUI BIAN JI SUAN QI SHE JI$" TAB2 DB 13,10," 1 2 3 4 $" TAB3 DB 13,10," 5 6 7 8 $" TAB4 DB 13,10," 9 0 + - $" TAB5 DB 13,10," * / ( ) $" TAB6 DB 13,10," PLEASE INPUT A FORMULA: $" TAB7 DB 13,10,"$" NUM1 DW 100 DUP(?) NUM3 DW 100 DUP(?) NUM4 DW 100 DUP(?) C0 DW 0 C1 DW 0 C2 DW 0 SUM1 DW 0 SUM2 DW 0 OLT DW 0 RESULT DW 0 TABLE DW 10000,1000,100,10,1 ;定义输出时要用到的除数 WRONG DB 13,10,"WRONG INPUT!$" ;OVER DB 13,10,"NOT OPERATIONAL CHARACTER!$" DATA ENDS ;---------------------------- ;------代码段---------------- CODE SEGMENT ASSUME CS:CODE,DS:DATA ;------主程序--------------- START: MOV AX,DATA MOV DS,AX CALL DISPMENU ; 显示汇编计算器菜单 STARTA: MOV BX,-1 MOV SI,0 MOV DI,30 MOV CX,0 MOV C0,0 MOV C1,0 MOV C2,0 ; 初始化各个变量 CALL INPUT CALL YUNSUAN CALL OUTPUT EXIT: MOV AH,4CH INT 21H ;------计算器显示菜单子程序-------- DISPMENU PROC NEAR MOV DX,OFFSET TAB1 MOV AH,09H INT 21H MOV DX,OFFSET TAB2 MOV AH,09H INT 21H MOV DX,OFFSET TAB3 MOV AH,09H INT 21H MOV DX,OFFSET TAB4 MOV AH,09H INT 21H MOV DX,OFFSET TAB5 MOV AH,09H INT 21H MOV DX,OFFSET TAB6 MOV AH,09H INT 21H MOV DX,OFFSET TAB7 MOV AH,09H INT 21H RET DISPMENU ENDP ;--------------------------- ;输入字符及转换程序模块 ;----输入并转换子程序,结果式存入NUM1------- INPUT PROC NEAR STARTW: MOV AH,1 INT 21H MOV AH,0 CMP AL,1BH ; 'ESC' JZ EXIT CMP AL,2AH ; '*' JZ MARK CMP AL,2FH ; '/' JZ MARK CMP AL,2BH ; '+' JZ MARK CMP AL,2DH ; '-' JZ MARK CMP AL,29H ; ')' JZ MARK CMP AL,28H ; '(' JZ MARK CMP AL,3DH ; '=' JZ EQUAL SUB AL,30H CMP AL,0 JL ERROR CMP AL,9 JA ERROR JMP ARITH ERROR: ;显示输入错误 LEA DX,WRONG MOV AH,9 INT 21H JMP STARTA ARITH: CMP C1,0 JE TTOM MANA: ;数值的补码转换 MOV C0,AX ADD C1,1 MOV AX,BX MOV CX,10 MUL CX ADD AX,C0 MOV BX,AX JMP STARTW TTOM: MOV BX,0 JMP MANA MARK: CMP BX,-1 JE GGON MOV NUM1[SI],BX ADD SI,2 MOV NUM1[SI],AX MOV BX,-1 MOV C1,0 ADD SI,2 JMP STARTW GGON: MOV NUM1[SI],AX ADD SI,2 JMP STARTW EQUAL: ;输入是等号时,调到主程序执行运算 CMP BX,-1 JE LLOP MOV NUM1[SI],BX ADD SI,2 MOV NUM1[SI],AX JMP ENDW LLOP: MOV NUM1[SI],AX JMP ENDW ENDW: RET INPUT ENDP ;--------------------------- ;-----运算的子程序---------- ; 使括号内的运算先进行,别用算出的结果代替对应括号及括号内的运算的子程序 YUNSUAN PROC NEAR AAAA: MOV BP,0 MOV DI,0 MOV BX,0 MOV C0,0 MOV C1,0 MOV SUM2,0 MOV SI,0 BBBB: MOV AX,NUM1[SI] CMP AX,29H ; ) 先查找最左边的右括号 JE RSEE ADD SI,2 CMP AX,3DH ; = JE LASTL JMP BBBB RSEE: SUB SI,2 MOV AX,NUM1[SI] CMP AX,28H ; ( JE MOTT JMP RSEE MOTT: MOV SUM2,SI MOV DI,0 KKTY: ADD SI,2 MOV AX,NUM1[SI] MOV NUM3[DI],AX ;把括号里的计算式存入NUM3 CMP AX,29H ; ) JE RCOUNT ADD DI,2 JMP KKTY RCOUNT: MOV SUM1,SI CALL CALC MOV DI,SUM2 MOV AX,RESULT MOV NUM1[DI],AX MOV SI,SUM2 CCOO: ADD SI,2 ADD DI,2 MOV AX,NUM1[SI] MOV NUM1[DI],AX CMP AX,3DH ; = JE AAAA JMP CCOO LASTL: MOV SI,0 UUCC: MOV AX,NUM1[SI] MOV NUM3[SI],AX ADD SI,2 CMP AX,3DH ; = JE ENDL JMP UUCC ENDL: CALL CALC RET YUNSUAN ENDP ;--------------------------------- ;------ 计算混合运算的子程序(不含括号的)------------------ CALC PROC NEAR MOV AX,NUM3 MOV NUM4,AX MOV DI,2 MOV C0,SI MOV SI,2 INT1: MOV BX,NUM3[SI] CMP BL,2AH ;'*' JE MULL CMP BL,2FH ;'/' JE DIVV CMP BL,3DH ;'=' JE CHUBU CMP BL,29H ;')' JE CHUBU CMP BL,2BH ;'+' JE POTT CMP BL,2DH ;'-' JE POTT INT2: MOV NUM4[DI],BX ADD DI,2 ADD SI,2 MOV AX,NUM3[SI] MOV NUM4[DI],AX ADD DI,2 ADD SI,2 JMP INT1 POTT: SUB DI,2 MOV NUM4[DI],AX ADD DI,2 JMP INT2 MULL: ADD SI,2 MOV BX,NUM3[SI] MUL BX ADD SI,2 JMP INT1 DIVV: ADD SI,2 MOV BX,NUM3[SI] DIV BX ADD SI,2 JMP INT1 ADDD: ADD DI,2 MOV BX,NUM4[DI] ADD AX,BX ADD DI,2 JMP INT3 SUBB: ADD DI,2 MOV BX,NUM4[DI] SUB AX,BX ADD DI,2 JMP INT3 CHUBU: MOV NUM4[DI],BX SUB DI,2 MOV NUM4[DI],AX MOV AX,NUM4 MOV DI,2 INT3: MOV BX,NUM4[DI] CMP BX,2BH ;'+' JE ADDD CMP BX,2DH ;'-' JE SUBB MOV RESULT,AX RET CALC ENDP ;--------------------------------- ;-----输出最终结果的子程序--------------- OUTPUT PROC NEAR LEA SI,TABLE MOV C0,SI ADD C0,8 MOV CX,5 MOV AX,RESULT MOV OLT,0 OUTT: XOR DX,DX ;异或清零 DIV WORD PTR [SI] ;求万位,千位,百位,十位,个位 ;商存在了AX中,余数存在了DX中 OR AL,30H ;转换成ASCLL码 MOV BX,DX ;将DX的值存入BX中,因为下面输出AX值时会改变DX值 CMP SI,C0 JE OUT2 CMP OLT,0 JNE OUT2 CMP AX,30H JE OUT1 JNE AADD OUT2: MOV DX,AX ;输出商值 MOV AH,02 INT 21H OUT1: MOV AX,BX ;将余数赋还给AX 因为除数十16位,所以余数在DX中 ADD SI,2 ;BP加二,用以调用下一个被除数 LOOP OUTT CALL ENTER JMP STARTA ;跳回程序开始 RET AADD: INC OLT JMP OUT2 OUTPUT ENDP ;--------------------------------- ;---------回车换行的子程序--------------------- ENTER PROC NEAR MOV DL,0DH ;回车 MOV AH,02H INT 21H MOV DL,0AH ;换行 MOV AH,02H INT 21H RET ENTER ENDP CODE ENDS END START
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传
相似文档                                   自信AI助手自信AI助手

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:4009-655-100  投诉/维权电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服