计算器设计。在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