题目描述:
计算器设计。在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
结果示例: