汇编计算器Word文件下载.docx
《汇编计算器Word文件下载.docx》由会员分享,可在线阅读,更多相关《汇编计算器Word文件下载.docx(18页珍藏版)》请在冰豆网上搜索。
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。
数值的补码转换流程如图4所示,当然,在获得第一个数值输入前要先把原值设置为0。
图4数值的补码转换流程图
由于符号全部是一个字节,无需进行任何转换即可保存,处理简单,这里不作探讨。
5.2计算
由于运算表达式有多个数值和符号,而符号有不同的优先级别,因此上文提到的数值保存和符号保存应该分开两个地方进行保存,这样有利于表达式的计算算法设计。
下面把“+、-、*、/”称为运算符,把“(、)”称为优先符。
图5运算表达式的存储举例
观察图5的三条运算表达式,再联系四则混合运算的优先原则,可以归纳出几点:
(a)数值的数量是运算符的数量加1(优先符不算),第1个运算符代表第1、2个数值的运算操作,第N个运算符代表第N、N+1个数值的运算操作……
(b)每进行一次运算,相应的运算符即被消除,而参与运算的两个数值合并为一个数值,仍然满足(a)。
例如图5(a),当完成乘法运算后,数值存储区有408、56两个数,符号存储区有“+”一个运算符。
(c)括号(优先符)的作用是把括号内的运算符的优先级别提高到比外部高。
因此,要实现运算表达式的运算,最重要的就是确定所有运算符的优先级别。
下面讨论运算符优先级别的编程设计方法。
5.2.1运算优先级别的静态确定法
此方法是完成了把整条运算表达式全部存入数值存储区和符号存储区后才开始对运算符优先级进行判断的方法:
⏹设置“*、/”的优先级为2、“+、-”的优先级为1;
⏹括号内部的所有运算符的优先级全部加2。
运用优先级别静态确定法处理图5的三条表达式的运算符,结果如图6所示。
其中图6(c)的“34+56-8”由于被括号括起两次,因此其两个运算符“+、-”的优先级别均加了两次2。
图6运算符的静态优先级别
最后,由于四则混合运算遵循从左往右计算的原则,即相同优先级别的运算符靠左的优先。
因此,只需计算出符号存储区里面的所有运算符的优先级别,然后根据优先级的大小先后执行运算符对应的运算即可实现计算(当然每进行一次运算,相应的运算符即被消除,而参与运算的两个数值合并为一个数值)。
当数值存储区里面剩下一个数值时,运算结束,这个最后的数值就是运算的最终结果。
请同学们自行设计此算法的流程图。
5.2.2运算优先级别的动态确定法
运算优先级别静态确定法具有容易理解、实现简单的优点,而其缺点是:
如果运算表达式太长、太多数值和符号时,则会占用较多的存储空间,而且计算优先级的工作量也会增多。
动态确定法是在运算表达式未结束输入即开始计算的一种方法。
由于在表达式输入阶段已开始计算,因此计算结果的速度比静态确定法快。
观察图5(a),当用户输入“+”时,已经可以开始计算“12*34”;
观察图5(b),当用户输入“-”时,已经可以开始计算“34+56”;
观察图5(c),当用户输入第一个“-”时,已经可以开始计算“12*21”。
也就是说,当用户输入的运算符的优先级不大于前一个运算符时,即可开始前一个运算符的计算。
问题是,对于有括号的运算表达式,在用户没有完成运算表达式的全部输入前,很难提前确定括号内部运算符的优先级。
为了解决这个问题,动态确定法把优先符(括号)也赋予了优先级:
⏹“(”,优先级为5;
⏹“*、/”,优先级为4;
⏹“+、-”,优先级为3;
⏹“)”,优先级为1。
计算图5三条运算表达式的所有符号的优先级别,结果如图7所示。
图7运算符的动态优先级别
设计计算的条件:
(1)只有优先级为3、4的符号(即+、-、*、/)可以进行计算;
(2)如果某符号的优先级大于等于下一个的优先级时,对此符号进行相应运算(当然每进行一次运算,相应的运算符即被消除,而参与运算的两个数值合并为一个数值);
(3)如果左右括号相邻,且左括号在右括号左边时(即在符号存储区里面出现“()”的情况,或者在优先级队列里出现“51”的情况),把这对括号消除掉。
最后,当数值存储区里面剩下一个数值(或者符号存储区里面没有符号)时,运算结束,这个最后的数值就是运算的最终结果。
请同学们自行设计此算法的流程图。
5.3结果输出
当数值存储区里面剩下一个数值(或者符号存储区里面没有符号)时,运算结束,需要把运算结果输出显示。
分析运算结果的特点:
运算结果为一个2进制补码,整数,如果数据长度为16位,则运算结果范围是:
-32768~32767。
运算结果的输出要解决的主要问题是:
正负数区分、补码到ASCII码转换并输出显示。
运算结果的输出流程如图8所示。
图8结果输出流程图
5.3.1正负数区分
运算结果有三种情况:
正整数、负整数、零。
运算结果以补码形式对这三种情况进行统一的存储,但显示输出时则有所不同。
负整数前面需要显示“-”号,因此需要对运算结果的符号进行判断。
另一方面,正整数和零的补码与原码相同,而负整数的补码则不一样。
把负整数进行取补码运算,把它转换为原码,可以实现运算结果统一的ASCII码转换输出方法,而不需要分别为正整数和零、负整数分别设计两个不同的ASCII码转换程序,如图9所示。
图9正负数区分流程图
5.3.2补码到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”,跟期望显示的顺序相反,要作进一步处理。
处理方法是把余数放进堆栈里面,然后再出栈显示。
由于堆栈是先进后出的,即可解决该输出的顺序问题。
图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”。
该方法的缺点是:
必须首先确定要输出的数值有多少位,编程者必须十分清楚需要输出的数值的数值范围。
图11除最高位法流程图
6得出的程序
;
-----------------------------------------------------------------------------
----------------------------数据定义-----------------------------------------
DSEGSEGMENT
STR1DB0AH,0DH,'
********************************************$'
STR2DB0AH,0DH,'
****$'
STR3DB0AH,0DH,'
**welcomeyou!
**$'
STR4DB0AH,0DH,'
STR5DB0AH,0DH,'
**thisisprogrammeofsizeyunshuan**$'
STR6DB0AH,0DH,'
**rang(-32768to32767)**$'
STR7DB0AH,0DH,'
**pressqtoexit!
STR8DB0AH,0DH,'
**copyrightbylinjieling**$'
STR9DB0AH,0DH,'
**pleaseinputtheformula:
STR10DB0AH,0DH,'
SIGN1DW0;
判断数字是否输入完毕
SIGN2DW0;
判断括号是否配对
NUMBDW20HDUP(0);
保存输入的数值
MARKDB'
A'
;
保存输入的运算符
DB10HDUP(0);
ERRORDB'
YOURINPUTAREWRONG$'
DSEGENDS
----------------------------宏定义-----------------------------------------
DISPMACROM;
字符串输出
LEADX,M;
将M的偏移地址传送给DX寄存器
MOVAH,9;
其中09H是字符串输出
INT21H;
通过给AH寄存器赋值,再调用INT21H指令,根据AH寄存器中的值执行相应的操作
ENDM
CHOICEMACROASC1,HAO1,HH;
宏定义,给运算符赋权值
CMPAL,ASC1;
比较键盘输入的运算符(运算符的ASC码存放在AL寄存器)与ASC1
JNEOTHER&
HAO1;
若不等,则往下执行OTHER1,如此类推
MOVCH,HH;
将运算符的权值(即优先级高低值)传送到CH寄存器
JMPOTHER7;
执行后,返回
----------------------------------------------------------------------------
CSEGSEGMENT;
ASSUMECS:
CSEG,DS:
DSEG
START:
CALLCLEAR
MOVAX,DSEG;
MOVDS,AX;
LEADI,NUMB;
将NUMB的偏移地址传送到DI,NUMB存储单元中存放输入的数值
LEASI,MARK;
将MARK的偏移地址传送到SI,MARK存储单元中存放输入的运算符
DISPSTR1;
显示字符串
DISPSTR2
DISPSTR3
DISPSTR4
DISPSTR5
DISPSTR6
DISPSTR7
DISPSTR8
DISPSTR9
DISPSTR10
MOVAX,0;
数据寄存器清零
MOVDX,0
MOVBX,0
MOVCX,0
STA1:
CALLCR;
回车换行
--------------------------------初始化-------------------------------------
INPUT:
MOVAH,1;
其中1H是键盘输入并回显,AL中有输入字符
INT21H;
--------------------------------输入字符-----------------------------------
CMPAL,'
q'
JEJ_SHU
----------------------------若输入q,则返回dos状态--------------------------
CMPAL,'
='
JEPD;
判断配对标志位
--------------------是等号,进一步判断输入括号是否配对----------------------
CMPAL,28H;
JBBC;
JB为小于就跳转
CMPAL,39H;
JABC;
JA为大于就跳转
-------------------输入字符的ASC码小于28H或大于39H,则继续输入--------------
CMPAL,2FH;
判断是数字还是符号
JBEJUD;
是符号转入响应操作
INCWORDPTRSIGN1;
将数字标志位加1
SUBAL,30H;
将ASC码转16进制
MOVAH,0;
XCHGAX,[DI];
互换两个操作数的存放位置,实现字交换
MOVBX,10;
MULBX;
无符号数乘法指令
ADD[DI],AX;
JMPINPUT;
-------------------------输入为数值时的操作----------------------------------
PD:
CMPWORDPTRSIGN2,0;
JEJUD;
跳到判断数值是否输入完毕
JMPBC;
不配对则显示ERROR
JUD:
CMPWORDPTRSIGN1,0;
判断数值是否输入完毕
JEFUH1;
跳到判断优先级
ADDDI,2;
DI向下移一个字
MOVWORDPTRSIGN1,0;
数值标志位清零
FUH1:
CALLADVANCE;
判定优先级
CMPCH,5;
判断输入的运算符中是否有左括号
JNEPY;
不是,则判断输入的运算符中是否有右括号
INCWORDPTRSIGN2;
是左括号,括号标志位加1
PY:
CMPCH,1;
判断输入的是否是右括号
JNEAGAIN;
跳到判断运算存储区是否为空
DECWORDPTRSIGN2;
是右括号,括号标志位减1
AGAIN:
CMPBYTEPTR[SI],'
判断运算符存储区是否为空
JESAVE;
判断输入是否为=
CMPCH,[SI];
JASAVE;
计算高优先级的SI指向运算符,每个运算符都有相应的权值
CMPBYTEPTR[SI],'
('
JNEYIDO;
寻找左括号
DECSI;
是左括号,还是向上移,判断左括号前边是否还有运算符
JMPINPUT;
----------------------------------------------------------------------------
YIDO:
DECSI;
SI向上移
MOVCL,[SI];
将运算符传送给CL
CALLMATCH;
判断是什么运算符并进行相应的计算
JMPAGAIN;
SAVE:
CMPCH,0;
JEOVER;
=时,则输出结果
CMPCH,1;
JEINPUT;
“)”不保存,输入下一个数
INCSI;
MOV[SI],AL;
JNEGO_ON;
MOVCH,2;
改变(的权值
GO_ON:
MOV[SI],CH;
BC:
LEADX,ERROR;
将ERROR的偏移地址给DX
MOVAH,9;
CALLCR
JMPJ_SHU1;
----------------------------四则运算子程序----------------------------------
MATCHPROC;
子程序,进行相应的运算
PUSHAX;
XORAX,AX;
异或
XORBX,BX
----------------------------乘法运算---------------------------------------
CMPCL,2AH;
乘法运算
JNENEXT1
SUBDI,2
XCHGBX,[DI]
XCHGAX,[DI]
IMULBX
MOV[DI],AX
ADDDI,2
JMPFINISH
---------------------------------------------------------------------------
----------------------------除法运算---------------------------------------
NEXT1:
CMPCL,2FH;
除法运算
JNENEXT2
SUBDI,2
CWD
IDIVBX
----------------------------加法运算---------------------------------------
NEXT2:
CMPCL,2BH;
加法运算
JNENEXT3
ADD[DI],BX
----------------------------减法运算--