汇编语言之计算器设计

题目描述:  

  计算器设计。在PC机上实现从键盘读入数据,并完成加、减、乘、除的计算。要求:1)屏幕上显示一个主菜单,提示用户输入相应的数字键,分别执行加、减、乘、除4种计算功能和结束程序的功能。若按其他键,则显示提示输入出错并要求重新输入,并继续显示主菜单。分别按数字键“1”、“2”、“3”,则执行相应子模块1、2、3,进行两个字节与两个字节的加法、减法和乘法运算,并在屏幕上显示运算结果。按数字键“4”,执行模块4,进行两字节除一个字节的除法运算。按数字键“5”,程序退出,返回DOS;2)要使用到子程序。

 

代码:

  1 enterline macro        ;定义回车换行的宏指令
  2     mov dl,13
  3     mov ah,2
  4     int 21h
  5     mov dl,10
  6     mov ah,2
  7     int 21h
  8 endm
  9 
 10 DATAS SEGMENT
 11     menus db'                         MENU$'
 12     input db'            Please select a function!$'
 13     number db'         1-add, 2-sub, 3-mult, 4-div, 5-exit$'
 14     a db'You are adding. Please enter two numbers separated by a space$'
 15     s db'You are subtracting. Please enter two numbers separated by a space$'
 16     m db'You are in the process of multiplication. Please enter two numbers separated by a space$'
 17     d db'You are in the process of division.Please enter two numbers separated by a space$'
 18     e db'Exiting program$'
 19     
 20     err db 'Illegal input! Please Try Again$'
 21     again db'Invalid input, try again.$'
 22     overout db'The number overflowed, try again$'
 23     err1 db'The result is overflowed, try again$'
 24     command db ?
 25     flag db ?
 26     temp dw 0
 27     buf db 20,?,20 dup(0)    ;定义键盘接收字符缓冲区,最多接收19个字符
 28     ff db ?        ;输出的判断前导0的标志
 29     
 30     op1 dw ?    ;定义两个操作数(16位)
 31     op2 dw ?
 32     
 33     hex_buf db 4 dup(30h),'H'
 34     crlf db '$'            ;这是一个字符串的结尾符号,紧跟在缓冲区后可形成字符串,丢失后会产生
 35 DATAS ENDS
 36 
 37 STACKS SEGMENT
 38     ;此处输入堆栈段代码
 39 STACKS ENDS
 40 
 41 CODES SEGMENT
 42     ASSUME CS:CODES,DS:DATAS,SS:STACKS
 43 START:
 44     MOV AX,DATAS
 45     MOV DS,AX
 46     ;此处输入代码段代码
 47     
 48 ;注意每次做完了计算都要回到主菜单
 49 menu:        ;菜单部分
 50     lea dx,menus
 51     mov ah,9
 52     int 21h
 53     enterline
 54     
 55     lea dx,input
 56     mov ah,9
 57     int 21h
 58     enterline
 59     
 60     lea dx,number
 61     mov ah,9
 62     int 21h
 63     enterline
 64     
 65     mov ah,1            ;字符存在AL里面
 66     int 21h
 67     
 68 judge:                    ;判断执行哪个功能
 69     cmp al,'1'
 70     je a1
 71     
 72     cmp al,'2'
 73     je a2
 74     
 75     cmp al,'3'
 76     je a3
 77     
 78     cmp al,'4'
 79     je a4
 80     
 81     cmp al,'5'
 82     je stop
 83     
 84     ;上面匹配都不成功,则把输入当成无效的输入,要求重新输入
 85     enterline
 86     lea dx,again
 87     mov ah,9
 88     int 21h
 89     enterline
 90     jmp menu
 91     
 92 a1:                    ;加法模块        ;设计完加法子程序后把下面这部分也封装进去
 93     enterline        ;这部分是输出提示性语句
 94     lea dx,a
 95     mov ah,9
 96     int 21h
 97     enterline
 98     
 99     call inputi        ;调用输入的子程序
100     cmp flag,1
101     je a1            ;由于错误输入跳回a1重新进行加法操作
102     cmp flag,2
103     je a1            ;由于溢出跳回a1重新输入
104     
105     call addi        ;调用加法子程序
106     cmp flag,2
107     je over
108     call outi
109     jmp menu        ;执行完后跳回主菜单
110     
111 over:
112     mov ax,op1
113     call to16str;将十进制转化为十六进制
114     mov dx,offset hex_buf
115     mov ah,9
116     int 21h
117     
118     mov ax,op2
119     call to16str;将十进制转化为十六进制
120     mov dx,offset hex_buf
121     mov ah,9
122     int 21h
123     enterline
124     jmp menu        ;执行完后跳回主菜单
125 a2:                    ;减法模块
126     enterline
127     lea dx,s
128     mov ah,9
129     int 21h
130     enterline
131     
132     call inputi        ;调用输入的子程序
133     cmp flag,1
134     je a2            ;由于错误输入跳回a1重新进行加法操作
135     cmp flag,2
136     je a2            ;由于溢出跳回a1重新输入
137     
138     call subi
139     call outi
140     jmp menu        ;执行完后跳回主菜单
141 
142 a3:                    ;乘法模块
143     enterline
144     lea dx,m
145     mov ah,9
146     int 21h
147     enterline
148     
149     call inputi        ;调用输入的子程序
150     cmp flag,1
151     je a3            ;由于错误输入跳回a1重新进行加法操作
152     cmp flag,2
153     je a3            ;由于溢出跳回a1重新输入
154     
155     call multi
156     
157     mov ax,op1
158     call to16str;将十进制转化为十六进制
159     mov dx,offset hex_buf
160     mov ah,9
161     int 21h
162     
163     mov ax,op2
164     call to16str;将十进制转化为十六进制
165     mov dx,offset hex_buf
166     mov ah,9
167     int 21h
168     enterline
169     
170     jmp menu        ;执行完后跳回主菜单
171 
172 a4:                    ;除法模块
173     enterline
174     lea dx,d
175     mov ah,9
176     int 21h
177     enterline
178     
179     call inputi        ;调用输入的子程序
180     cmp flag,1
181     je a4            ;由于错误输入跳回a1重新进行加法操作
182     cmp flag,2
183     je a4            ;由于溢出跳回a1重新输入
184     
185     call divi
186     cmp flag,1
187     je a4            ;由于除数可能输0导致重新输入
188     call outi
189     jmp menu        ;执行完后跳回主菜单
190 
191 stop:        ;程序的结束
192     enterline
193     lea dx,e
194     mov ah,9
195     int 21h
196     
197     MOV AH,4CH
198     INT 21H
199  
200 
201 inputi proc            ;输入子程序如下
202     mov flag,0        ;初始化flag
203     
204     lea dx,buf        ;从键盘接收输入数值放入buf缓冲区(输入操作)
205     mov ah,10
206     int 21h
207     enterline        ;回车换行
208     
209     
210     mov cl,buf+1    ;获取实际键入字符数,置于CX寄存器中
211     xor ch,ch        ;ch清0
212     
213     xor di,di        ;累加器清0
214     xor dx,dx        ;dX寄存器清0
215     mov bx,1        ;由于从个位数开始算起,因而将所乘权值设为1
216     
217     lea si,buf+2    ;将si指向接收到的第1个字符位置
218     add si,cx        ;因为从个位算起,所以将si指向最后1个接收到的个位数
219     dec si            ;往回减1使其指向字串最后一个元素
220 
221 ;cov是检测并生成第一个数字的步骤
222 cov:mov al,[si]        ;取出个位数给al
223     cmp al,' '        
224     jz next1        ;遇见空格则跳转
225     
226     cmp al,'0'        ;边界检查:如果输入不是0-9的数字,就报错
227     jb wrong
228     cmp al,'9'
229     ja wrong
230     
231     sub al,30h        ;将al中的ascii码转为数字
232     xor ah,ah
233     mul bx            ;乘以所处数位的权值
234     cmp dx,0        ;判断结果是否超出16位数范围,如超出则报错
235     jne yichu
236     
237     add di,ax        ;将形成的数值叠加放在累加器di中
238     jc yichu        ;CF是进位标志
239  
240     mov ax,bx        ;将BX中的数位权值扩大10倍,此处需要借助ax来实现
241     mov bx,10
242     mul bx
243     mov bx,ax
244     
245     dec si            ;si指针减1,指向前一数位
246     loop cov        ;按CX中的字符个数计数循环
247        
248 ;跳到次处表明第一个数字已经生成,接着去检测第二个数字    
249 next1:
250     mov op1,di        ;将结果储存在op1中4
251     xor ax,ax
252     xor di,di        ;累加器清0
253     xor bx,bx
254     mov bx,1        ;由于从个位数开始算起,因而将所乘权值设为1
255     dec si        ;向前移动一格位置
256     dec cx        ;遇到空格cx相应的减少1
257 
258 
259 ;cov2是检测并生成第2个数字
260 cov2:
261     mov al,[si]        ;取出个位数给al
262 
263     cmp al,'0'        ;边界检查:如果输入不是0-9的数字,就报错
264     jb wrong
265     cmp al,'9'
266     ja wrong
267     
268     sub al,30h        ;将al中的ascii码转为数字
269     xor ah,ah
270     mul bx            ;乘以所处数位的权值
271     cmp dx,0        ;判断结果是否超出16位数范围,如超出则报错
272     jne yichu
273     
274     add di,ax        ;将形成的数值放在累加器di中
275     jc yichu        ;CF是进位标志
276         
277     mov ax,bx        ;将BX中的数位权值扩大10倍,此处需要借助ax来实现
278     mov bx,10
279     mul bx
280     mov bx,ax
281     
282     dec si            ;si指针减1,指向前一数位
283     loop cov2        ;按CX中的字符个数计数循环
284     
285 next2:
286     mov op2,di        ;将结果储存在op2中
287     jmp return        ;结束后跳到return部分
288     
289 wrong:
290     lea dx,err
291     mov ah,9
292     int 21h
293     mov flag,1
294     jmp return
295     
296 yichu:
297     mov flag,2
298     lea dx,overout
299     mov ah,9
300     int 21h
301     
302 return:
303     ret
304 inputi endp
305 
306 addi proc    ;加法子程序(16位数相加)
307     xor bx,bx
308     xor cx,cx
309     mov bx,op2
310     mov cx,op1
311     add bx,cx
312     cmp bx,op1
313     jb ex
314     cmp bx,op2
315     jb ex
316     jmp addret
317 ex:                    ;表示结果高于16位的加法操作
318     mov flag,2
319     mov op2,bx
320     mov op1,1        ;表示进位
321     
322 addret:
323     ret
324 addi endp 
325 
326 subi proc    ;减法子程序(16位数相减)
327     xor bx,bx
328     xor cx,cx
329     mov bx,op2
330     mov cx,op1
331     cmp bx,cx        ;比较大小
332     jb fuhao
333     sub bx,cx        ;结果储存在bx中        
334     jmp subret
335 fuhao:    
336     mov dx,'-'
337     mov ah,2
338     int 21h
339     sub cx,bx
340     mov bx,cx
341 subret:
342     ret
343 subi endp
344 
345 multi proc    ;乘法子程序(16位数相乘)
346     xor ax,ax
347     xor cx,cx
348     mov ax,op2
349     mov cx,op1
350     mul cx            ;结果存在dx:ax里面
351     mov op1,dx
352     mov op2,ax        ;暂存在op1和op2
353     ret
354 multi endp 
355 
356 divi proc    ;除法子程序(16位数除以8位数)
357     xor bx,bx            ;注意 该程序的除数不能超过255 并且商也不能超过255 他们的承载能力只有8位
358     xor cx,cx
359     xor ax,ax
360     mov cx,op1            ;实际上存在cl中
361     cmp cx,255            ;让cx的值处于0~255之间(因为寄存器是8位的)
362     ja divwrong
363     cmp cl,0
364     je divwrong
365     mov al,255            ;让255和op1相乘,与op2比较,若小于op2则会发生divide error因此判断非法
366     mul cl
367     cmp ax,op2
368     jb overflow
369     
370     mov ax,op2
371     div cl                ;字除以1字节型除法,商存在al中
372     mov ah,0            ;清除ah中的内容
373     mov bx,ax
374     jmp divret
375 divwrong:
376     lea dx,err
377     mov ah,9
378     int 21h
379     mov flag,1
380 overflow:
381     lea dx,err1
382     mov ah,9
383     int 21h
384     mov flag,1
385 divret:
386     ret
387 divi endp 
388 
389 outi proc
390     mov ax,bx            ;待输出的数先存在bx里面,在给ax
391     mov bx,10000        ;初始数位权值为10000
392     mov ff,0            ;每次都赋初值0
393     
394 cov1:xor dx,dx            ;将dx:ax中的数值除以权值
395     div bx
396     mov cx,dx            ;余数备份到CX寄存器中
397     
398     cmp ff,0            ;检测是否曾遇到非0商值
399     jne nor1            ;如遇到过,则不管商是否为0都输出显示
400     cmp ax,0            ;如未遇到过,则检测商是否为0
401     je cont                ;为0则不输出显示    
402 nor1:
403     mov dl,al            ;将商转换为ascii码输出显示
404     add dl,30h
405     mov ah,2
406     int 21h
407     
408     mov ff,1            ;曾遇到非0商,则将标志置1
409 cont:
410     cmp bx,10            ;检测权值是否已经修改到十位了
411     je outer            ;如果相等,则完成最后的个位数输出显示
412     
413     xor dx,dx            ;将数位权值除以10
414     mov ax,bx
415     mov bx,10
416     div bx
417     mov bx,ax
418  
419     mov ax,cx            ;将备份的余数送入AX
420     jmp cov1                ;继续循环 
421 outer:
422     mov dl,cl            ;最后的个位数变为ascii码输出显示
423     add dl,30h
424     mov ah,2
425     int 21h   
426     enterline
427 ret
428 outi endp
429 
430 to16str proc;功能:将十进制转化为十六进制
431     mov bx,ax;将带转换的十进制数赋值给bx
432     mov si,offset hex_buf    ;将字符串的首地址赋值给si
433 
434     mov ch,4 ;将10进制转为4位16进制数,每次操作1位,ch为当前还需要转换的位数
435     loop_trans:
436     mov cl,4
437     rol bx,cl;此处cl的值为4,代表将BX中的值循环左移4位,bx中做该4位移动到最低4位
438     
439     mov al,bl;从高到低提取四位二进制数送入al,和0fh进行与操作得bl中低4位
440     and al,0fh
441     
442     add al,30h;al=0~9,加30h转化为ascii码
443     cmp al,3ah
444     jl next_trans
445     add al,7  ;al>9,加37h转化为ascii码,转换为字母A~F
446     
447     next_trans:
448     mov [si],al    ;将转换好的ascii码赋值给字符串的si位置处
449     inc si    ;si向后移动一位
450     dec ch    ;代表还需转换的位数减1
451     jnz loop_trans;注意,这儿只能用dec运算对标志位的设置来判断循环与否
452     ;因为cl被用来存放位移数了
453 ret
454 to16str endp
455 CODES ENDS
456     END START

 结果示例:

posted @ 2020-04-07 19:44  neverstopcoding  阅读(1771)  评论(0编辑  收藏  举报