DATAS SEGMENT
BUF1 DB 16
DB 0
DB 16 DUP(0)
BUF2 DB 16
DB 0
DB 16 DUP(0)
NUM2 Db ?
NUM DW ?
NUM1 DW ?
ANSWER DW 0
Signflag db ?
prompt1 db 'Enter the first number: $'
prompt2 db 'Enter the operator: $'
prompt3 db 'Enter the second number: $'
prompt4 db 'Result is: $'
prompt5 db 'The default input format for this calculator is binary, and the output format is decimal. You can indicate the input format by adding a suffix: b for binary,o for octal, and h for hexadecimal, after the input number.'
newline db 0Ah, 0Dh, '$'
DATAS ENDS
STACKS SEGMENT PARA STACK
DW 30H DUP(0)
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
mov ah, 09h
lea dx, prompt5
int 21h
mov ah, 09h
lea dx, prompt1
int 21h
CALL STOIA
lea dx, newline
mov ah, 09h
int 21h
mov ah, 09h
lea dx, prompt2
int 21h
MOV AH,1
INT 21H
mov Signflag, al
lea dx, newline
mov ah, 09h
int 21h
mov ah, 09h
lea dx, prompt3
int 21h
CALL STOIB
lea dx, newline
mov ah, 09h
int 21h
mov ah, 09h
lea dx, prompt4
int 21h
CALL OUTPT
MOV AH,4CH
INT 21H
STOIA PROC ;辗转相除法 将输入的十进制数转存到num中
MOV AH,0AH
LEA DX,BUF1
INT 21H ;读入数据
MOV DX,BUF1
MOV NUM,0
Mov bx,10
MOV AX,0
MOV SI,OFFSET BUF1+1
mov si,BUF1[si];
and si,00ffh
inc si
mov al,BUF1[si]
mov NUM2,al
cmp al,62h
jz isBinary1
cmp al,6Fh
jz isOctal1
cmp al,68h
jz isHexa1
cmp al,64h
jz isDeci1
isBinary1:
MOV BX,2
jmp goto1
isOctal1:
MOV BX,8
jmp goto1
isHexa1:
MOV BX,16
jmp goto1
isDeci1:
MOV BX,10
goto1 :
MOV SI,OFFSET BUF1+2
MOV AX,0
LOP:
MOV AL,BUF1[SI]
CMP AL,0DH
JE FINAL
CMP AL,62H
JE FINAL
CMP AL,6FH
JE FINAL
CMP AL,68H
JE FINAL
CMP AL,64H
JE FINAL
SUB AL,30H
CMP NUM,0
JE DO_DEAL
PUSH AX
MOV AX,NUM
MUL BX
MOV NUM,AX
POP AX
DO_DEAL:
ADD NUM,AX
MOV AX,0
INC SI
JMP LOP
FINAL:
RET
STOIA ENDP
STOIB PROC ;辗转相除法 将输入的十进制数转存到num中
LEA DX,BUF2
MOV AH,0AH
INT 21H ;读入数据
MOV DX,BUF2
MOV SI,OFFSET BUF2+2
Mov bx,10
MOV NUM1,0
MOV AX,0
MOV SI,OFFSET BUF2+1
mov si,BUF1[si];
and si,00ffh
inc si
mov al,BUF1[si]
cmp al,62h
jz isBinary2
cmp al,6Fh
jz isOctal2
cmp al,68h
jz isHexa2
cmp al,64h
jz isDeci2
isBinary2:
MOV BX,2
jmp goto2
isOctal2:
MOV BX,8
jmp goto2
isHexa2:
MOV BX,16
jmp goto2
isDeci2:
MOV BX,10
goto2 :
MOV SI,OFFSET BUF2+2
LOP1:
MOV AL,BUF1[SI]
CMP AL,0DH
JE FINAL1
CMP AL,62H
JE FINAL1
CMP AL,6FH
JE FINAL1
CMP AL,68H
JE FINAL1
CMP AL,64H
JE FINAL1
SUB AL,30H
CMP NUM1,0
JE DO_DEAL1
PUSH AX
MOV AX,NUM1
MUL BX
MOV NUM1,AX
POP AX
DO_DEAL1:
ADD NUM1,AX
MOV AX,0
INC SI
JMP LOP1
FINAL1:
RET
STOIB ENDP
OUTPT PROC
MOV AL,Signflag
CMP AL,'+'
JZ MYADD
CMP AL,'-'
JZ MYSUB
CMP AL,'*'
JZ MYMUL
CMP AL,'/'
JZ MYDIV
MYADD:
mov ax,NUM
add ax,NUM1
mov answer ,ax
jmp goon
MYSUB:
mov ax,NUM
sub ax,NUM1
mov answer ,ax
jmp goon
MYMUL:
mov ah,0
mov al,byte ptr NUM
mul byte ptr NUM1
mov answer ,ax
jmp goon
MYDIV:
mov ah,0
mov al,byte ptr NUM
div byte ptr NUM1
mov byte ptr answer , al
goon:
mov ax,ANSWER
push ax
mov al,byte ptr ANSWER
mov ah, 0
mov bx, 10
mov cx, 0
count_digits:
mov ah,0
mov al,byte ptr ANSWER
inc cx ; 增加计数器
div bl ; 除以10
mov byte ptr ANSWER ,al
cmp al,0 ; 判断商是否为0
jnz count_digits ; 如果不为0,继续循环
pop ax
mov ANSWER,ax
loop_start:
; 获取缓冲区的内容
mov al,byte ptr ANSWER
; 除法运算
xor ah,ah ; 清除高位寄存器
call power_of_10
div bl ; 除以BX寄存器中的数据
mov byte ptr answer,ah ; 更新缓冲区的内容为余数,即下一次循环的被除数
; 显示商
mov dl,al ; 存储要显示的字符
add dl,30h
mov ah,2h ; 显示字符的功能号
int 21h ; 调用DOS中断显示字符
; 循环次数减1
loop loop_start
OUTPT ENDP
power_of_10 proc
push ax ; 保存寄存器现场
push cx
mov ax, 1 ; 初始化结果为1
mov bx, 10 ; 初始化底数为10
dec cx
power_loop:
cmp cx, 0 ; 检查n是否为0
je power_end ; 如果是,跳出循环
mul bx ; 结果乘以底数
dec cx ; n减1
jmp power_loop ; 继续循环
power_end:
mov bx, ax ; 将结果保存到BX寄存器
pop cx
pop ax ; 恢复寄存器现场
ret
power_of_10 endp
CODES ENDS
END START
这个计算器默认的是2进制的输入,10进制的输出,你可以在输入时在末尾显示的输入b二进制,d十进制,o八进制,h十六进制,例如输入 10b ,13h
由于时间限制本计算器有些异常条件未进行处理,但本计算器保留了较好的接口,方便读者去自行扩展
例如以下就是案例
对该计算器改为了10进制的默认输入,并加上了除0异常报错
DATAS SEGMENT
BUF1 DB 16
DB 0
DB 16 DUP(0)
BUF2 DB 16
DB 0
DB 16 DUP(0)
NUM2 Db ?
NUM DW ?
NUM1 DW ?
ANSWER DW 0
Signflag db ?
prompt1 db 'Enter the first number: $'
prompt2 db 'Enter the operator: $'
prompt3 db 'Enter the second number: $'
prompt4 db 'Result is: $'
prompt5 db 'The default input format for this calculator is decimal , and the output format is decimal. You can indicate the input format by adding a suffix: b for binary,o for octal, and h for hexadecimal, after the input number.$'
prompt6 db 'division by zero$'
newline db 0Ah, 0Dh, '$'
DATAS ENDS
STACKS SEGMENT PARA STACK
DW 30H DUP(0)
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
mov ah, 09h
lea dx, prompt5
int 21h
lea dx, newline
mov ah, 09h
int 21h
mov ah, 09h
lea dx, prompt1
int 21h
CALL STOIA
lea dx, newline
mov ah, 09h
int 21h
mov ah, 09h
lea dx, prompt2
int 21h
MOV AH,1
INT 21H
mov Signflag, al
lea dx, newline
mov ah, 09h
int 21h
mov ah, 09h
lea dx, prompt3
int 21h
CALL STOIB
lea dx, newline
mov ah, 09h
int 21h
mov ah, 09h
lea dx, prompt4
int 21h
CALL OUTPT
MOV AH,4CH
INT 21H
STOIA PROC ;辗转相除法 将输入的十进制数转存到num中
MOV AH,0AH
LEA DX,BUF1
INT 21H ;读入数据
MOV DX,BUF1
MOV NUM,0
Mov bx,10
MOV AX,0
MOV SI,OFFSET BUF1+1
mov si,BUF1[si];
and si,00ffh
inc si
mov al,BUF1[si]
mov NUM2,al
cmp al,62h
jz isBinary1
cmp al,6Fh
jz isOctal1
cmp al,68h
jz isHexa1
cmp al,64h
jz isDeci1
isDeci1:
MOV BX,10
jmp goto1
isOctal1:
MOV BX,8
jmp goto1
isHexa1:
MOV BX,16
jmp goto1
isBinary1:
MOV BX,10
goto1 :
MOV SI,OFFSET BUF1+2
MOV AX,0
LOP:
MOV AL,BUF1[SI]
CMP AL,0DH
JE FINAL
CMP AL,62H
JE FINAL
CMP AL,6FH
JE FINAL
CMP AL,68H
JE FINAL
CMP AL,64H
JE FINAL
SUB AL,30H
CMP NUM,0
JE DO_DEAL
PUSH AX
MOV AX,NUM
MUL BX
MOV NUM,AX
POP AX
DO_DEAL:
ADD NUM,AX
MOV AX,0
INC SI
JMP LOP
FINAL:
RET
STOIA ENDP
STOIB PROC ;辗转相除法 将输入的十进制数转存到num中
LEA DX,BUF2
MOV AH,0AH
INT 21H ;读入数据
MOV DX,BUF2
MOV SI,OFFSET BUF2+2
Mov bx,10
MOV NUM1,0
MOV AX,0
MOV SI,OFFSET BUF2+1
mov si,BUF1[si];
and si,00ffh
inc si
mov al,BUF1[si]
cmp al,62h
jz isBinary2
cmp al,6Fh
jz isOctal2
cmp al,68h
jz isHexa2
cmp al,64h
jz isDeci2
isDeci2:
MOV BX,10
jmp goto2
isOctal2:
MOV BX,8
jmp goto2
isHexa2:
MOV BX,16
jmp goto2
isBinary2:
MOV BX,2
goto2 :
MOV SI,OFFSET BUF2+2
LOP1:
MOV AL,BUF1[SI]
CMP AL,0DH
JE FINAL1
CMP AL,62H
JE FINAL1
CMP AL,6FH
JE FINAL1
CMP AL,68H
JE FINAL1
CMP AL,64H
JE FINAL1
SUB AL,30H
CMP NUM1,0
JE DO_DEAL1
PUSH AX
MOV AX,NUM1
MUL BX
MOV NUM1,AX
POP AX
DO_DEAL1:
ADD NUM1,AX
MOV AX,0
INC SI
JMP LOP1
FINAL1:
RET
STOIB ENDP
OUTPT PROC
MOV AL,Signflag
CMP AL,'+'
JZ MYADD
CMP AL,'-'
JZ MYSUB
CMP AL,'*'
JZ MYMUL
CMP AL,'/'
JZ MYDIV
MYADD:
mov ax,NUM
add ax,NUM1
mov answer ,ax
jmp goon
MYSUB:
mov ax,NUM
sub ax,NUM1
mov answer ,ax
jmp goon
MYMUL:
mov ah,0
mov al,byte ptr NUM
mul byte ptr NUM1
mov answer ,ax
jmp goon
MYDIV:
mov ah,0
mov bl,byte ptr NUM
mov al,byte ptr NUM1
cmp al,0
jz unleg0
mov al,bl
div byte ptr NUM1
mov byte ptr answer , al
goon:
mov ax,ANSWER
push ax
mov al,byte ptr ANSWER
mov ah, 0
mov bx, 10
mov cx, 0
count_digits:
mov ah,0
mov al,byte ptr ANSWER
inc cx ; 增加计数器
div bl ; 除以10
mov byte ptr ANSWER ,al
cmp al,0 ; 判断商是否为0
jnz count_digits ; 如果不为0,继续循环
pop ax
mov ANSWER,ax
loop_start:
; 获取缓冲区的内容
mov al,byte ptr ANSWER
; 除法运算
xor ah,ah ; 清除高位寄存器
call power_of_10
div bl ; 除以BX寄存器中的数据
mov byte ptr answer,ah ; 更新缓冲区的内容为余数,即下一次循环的被除数
; 显示商
mov dl,al ; 存储要显示的字符
add dl,30h
mov ah,2h ; 显示字符的功能号
int 21h ; 调用DOS中断显示字符
; 循环次数减1
loop loop_start
jmp nounleg0
unleg0:
lea dx, newline
mov ah, 09h
int 21h
mov ah, 09h
lea dx, prompt6
int 21h
nounleg0:
OUTPT ENDP
power_of_10 proc
push ax ; 保存寄存器现场
push cx
mov ax, 1 ; 初始化结果为1
mov bx, 10 ; 初始化底数为10
dec cx
power_loop:
cmp cx, 0 ; 检查n是否为0
je power_end ; 如果是,跳出循环
mul bx ; 结果乘以底数
dec cx ; n减1
jmp power_loop ; 继续循环
power_end:
mov bx, ax ; 将结果保存到BX寄存器
pop cx
pop ax ; 恢复寄存器现场
ret
power_of_10 endp
CODES ENDS
END START