assembly - 原始计算器(+、-、*、/)。添加以十六进制表示法工作的能力
问题描述
我写了一个计算器,您可以在其中执行十进制和二进制系统的运算。我还尝试添加以十六进制表示法工作的能力,但认为它是错误的。请帮我弄清楚如何解决这个问题。
Calc
Used
B - 二进制
D - 十进制
+, -, *, / - 运算
= 或 ENTER - 显示结果并退出
表达式: (HEX)A+ (HEX)B = (DEC)5
按任意键退出...
这是程序代码:
LOCALS @@
.model tiny
.code
.386
org 100h
main proc
jmp start
OpMul equ '*'
OpDiv equ '/'
OpAdd equ '+'
OpSub equ '-'
CrLf db 0Dh, 0Ah, '$'
msgAbout db 'Calc', 0Dh, 0Ah
db 'Used', 0Dh, 0Ah
db 'B - binary base', 0Dh, 0Ah
db 'D - decimal base', 0Dh, 0Ah
db 'H - hex base', 0Dh, 0Ah
db '+, -, *, / - operations', 0Dh, 0Ah
db '= or ENTER - show result and quit', 0Dh, 0Ah, '$'
msgChangeBase2 db 08h, 08h, 08h, 08h, 08h
msgBase2 db ' (BIN)', '$'
msgChangeBase10 db 08h, 08h, 08h, 08h, 08h
msgBase10 db ' (DEC)', '$'
msgChangeBase16 db 08h, 08h, 08h, 08h, 08h
msgBase16 db ' (HEX)', '$'
msgPromptExpr db 0Dh, 0Ah, 'Expression: ', '$'
msgResult db 'Result: ', '$'
msgPressAnyKey db 0Dh, 0Ah, 'Press any key to exit...', '$'
Base dw ?
EnBaseChange dw ?
Operand1 dw ?
Operand2 dw ?
Operation db ?
OperationNext db ?
start:
mov ah, 09h
lea dx, [msgAbout]
int 21h
mov ah, 09h
lea dx, [msgPromptExpr]
int 21h
mov [Operand1], 0
mov [Operand1], 0
mov [Operation], OpAdd
mov [EnBaseChange], 1
mov [Base], 10
mov ah, 09h
lea dx, [msgBase10]
int 21h
@@GetCmd:
mov ah, 00h
int 16h
@@IsDigit:
cmp al, '0'
jb @@IsOperation
;;;;;;;;;;;;
;to enter letters from A to F for hexadecimal notation
cmp al, '9'+1
jb @@1
cmp al, 'A'
jb @@IsOperation
cmp al, 'F'
ja @@IsOperation
mov dl, al
mov ah, 0
sub al, 37h
jmp @@2
;;;;;;;;;;;;
@@1:mov dl, al
mov ah, 0
sub al, '0'
@@2:cmp ax, [Base]
jae @@GetCmd
push ax
mov ah, 02h
int 21h
pop ax
mov [EnBaseChange], 0
mov bx, 0
mov bl, al
mov ax, [Operand2]
mul [Base]
add ax, bx
mov [Operand2], ax
jmp @@GetCmd
@@IsOperation:
cmp al, 'a'
jb @@case
cmp al, 'z'
ja @@case
add al, 'A'-'a'
@@case:
cmp al, 0Dh
jne @@IsBase2
mov al, '='
@@IsBase2:
cmp al, 'B'
jne @@IsBase16
cmp [EnBaseChange], 1
jne @@GetCmd
mov [Base], 2
mov ah, 09h
lea dx, [msgChangeBase2]
int 21h
jmp @@GetCmd
;;;;;;;;;;;;;;;;;;;
@@IsBase16:
cmp al, 'H'
jne @@IsBase10
cmp [EnBaseChange], 1
jne @@GetCmd
mov [Base], 16
mov ah, 09h
lea dx, [msgChangeBase16]
int 21h
jmp @@GetCmd
;;;;;;;;;;;;;;;;;;;
@@IsBase10:
cmp al, 'D'
jne @@IsOp
cmp [EnBaseChange], 1
jne @@GetCmd
mov [Base], 10
mov ah, 09h
lea dx, [msgChangeBase10]
int 21h
jmp @@GetCmd
@@IsOp:
cmp al, OpAdd
je @@DoOperation
cmp al, OpSub
je @@DoOperation
cmp al, OpMul
je @@DoOperation
cmp al, OpDiv
je @@DoOperation
cmp al, '='
je @@DoOperation
jmp @@GetCmd
@@DoOperation:
mov [OperationNext], al
mov ax, [Operand1]
cwd
mov bx, [Operand2]
cmp [Operation], OpAdd
jne @@Sub
add ax, bx
jmp @@Calc
@@Sub:
cmp [Operation], OpSub
jne @@Mul
sub ax, bx
jmp @@Calc
@@Mul:
cmp [Operation], OpMul
jne @@Div
imul bx
@@Div:
cmp [Operation], OpDiv
jne @@Calc
idiv bx
@@Calc:
mov [EnBaseChange], 1
mov [Operand1], ax
mov [Operand2], 0
mov al, [OperationNext]
mov [Operation], al
int 29h
mov ah, 09h
lea dx, [msgBase2]
cmp [Base], 2
je @@ShowBase
lea dx, [msgBase10]
@@ShowBase:
int 21h
mov al, [Operation]
cmp al, '='
je @@Break
jmp @@GetCmd
@@Break:
mov ax, [Operand1]
mov bx, [Base]
call ShowUInt16
mov ah, 09h
lea dx, [msgPressAnyKey]
int 21h
mov ah, 00h
int 16h
int 20h
main endp
; Display on the screen a whole 16-bit unsigned number
; at the entrance:
; ax is an integer 16 bit unsigned number
ShowUInt16 proc
push ax
push bx
push cx
push dx
;mov bx, 10 ; divider (base of the number system)
mov cx, 0 ; number of displayed digits
@@div:
xor dx, dx ; divide (dx: ax) by bx
div bx
add dl, '0' ; convert the remainder of the division into a digit symbol
push dx ; and save it on the stack
inc cx ; increase the number counter
test ax, ax ; are there still numbers in the number?
jnz @@div ; yes - repeat the cycle of highlighting the number
@@show:
mov ah, 02h ; function ah = 02h int 21h - display a character from dl on the screen
pop dx ; extract the next digit from the stack
int 21h ; and display it on the screen
loop @@show ; and so do as many times as the numbers found in the number (cx)
pop dx
pop cx
pop bx
pop ax
ret
ShowUInt16 endp
end main
解决方案
您的评论准确地描述了问题:
例如:7D00 * 2 = FA00,但程序会给出?:00即不是字母F,而是符号? , 而不是字母 A 将有一个符号:
为什么是这样?
ShowUInt16 proc 最初是为处理 base-10 数字而编写的。一旦你开始将它用于以 16 为基数的数字,你必须准备好在更广泛的范围 [0,15] 中获得余数。
这是需要的更改:
- 对于余数 [0,9],加 48 以得到字符“0”-“9”
- 对于余数 [10,15],加 48再加上 7以得到字符“A”-“F”
; Display on the screen a whole 16-bit unsigned number
; at the entrance:
; ax is an integer 16 bit unsigned number
ShowUInt16 proc
push ax
push bx
push cx
push dx
mov bx, [Base] ; divider (base of the number system) {2,10,16}
xor cx, cx ; number of displayed digits
@@div:
xor dx, dx
div bx
add dl, '0' <<<<<<<<<
cmp dl, '9' <<<<<<<<<
jbe @@ok <<<<<<<<<
add dl, 7 <<<<<<<<<
@@ok: <<<<<<<<<
push dx
inc cx
test ax, ax
jnz @@div
@@show:
pop dx
mov ah, 02h ; DOS.PrintChar
int 21h
loop @@show
pop dx
pop cx
pop bx
pop ax
ret
ShowUInt16 endp
您的代码中有一个遗漏,在显示结果之前不显示(HEX)消息。您可能希望使用以下代码改进程序:
mov al, [Base]
lea dx, [msgBase2]
cmp al, 2
je @@ShowBase
lea dx, [msgBase10]
cmp al, 10 <<<<<<<<<
je @@ShowBase <<<<<<<<<
lea dx, [msgBase16] <<<<<<<<<
@@ShowBase:
mov ah, 09h
int 21h
mov al, [Operation]
cmp al, '='
je @@Break
jmp @@GetCmd
mov [Operand1], 0 mov [Operand1], 0
最后,这可能只是一个错字,您的代码将Operand1 归零两次,从而忘记了用于构建输入数字的重要Operand2 。这可以解释奇怪的数值异常......
为什么不添加一些完美呢?
随着您选择只接受大写字符“A”-“F”的十六进制表示法的引入,用户现在必须恢复使用小字符“b”、“d”和“h”来选择号码系统。您可能希望在您的msgAbout消息中反映此限制。
推荐阅读
- php - 如何从 CodeIgniter 3 连接到 SQL Server 数据库?
- ios - 在 Swift 中的过渡更改后移动事物
- mongodb - mongodb设置对象,其中键值动态变化
- view - CouchDB 多级视图地图功能?
- cakephp - cakephp 3.7 如何设置邮件布局和模板
- ios - iOS Application_Home/Library/Caches 目录经常被清除
- angular - 如果用户已经登录,则显示/隐藏我的菜单
- java - 如何通过多个id找到一些数据?
- docker - Windows 10 Linux 子系统中的 Dockerfile 在当前目录中找不到文件
- django - 每个用户的合同的首次记录开始日期、最后记录结束日期以及如何应用过滤器