📄 express.asm
字号:
;*************************************************************************
;题目:算式计算
;要求:输入一个由“+,-,*,/,()”组成的算式,运算结果为:-32767至+32768,计算并显示结果。
;提示:运用分支,循环,子程序等编程形式,运用键盘,显示器,文件的中断调用,显示时注意字符与符值的转换。
;*************************************************************************
mpush macro opr
sub di,2
mov word ptr[di],opr
endm
mpop macro opr
mov opr,word ptr[di]
add di,2
endm
npush macro opr
sub bx,2
mov word ptr[bx],opr
endm
npop macro opr
mov opr,word ptr[bx]
add bx,2
endm
;***********************************************************
data segment
n db 49,?
express db 50 dup(?)
db 52 dup(?) ;运算符栈
toem label word
db 10 dup(0) ;数字栈
toen label word
;标志
flag db ?
brace db 0
negate db ?
;提示信息
result db 13,10,"The result is $"
mess0 db 13,10,"Error:Invalid expression!",13,10,'$'
mess1 db 13,10,"Error:Over flow!",13,10,'$'
mess2 db 13,10,"Error:Divide zero.",13,10,'$'
table dw ?,addition,subtration,multiplication,division
data ends
stack segment
dw 30 dup(?)
toe label word
stack ends
;***********************************************************
code segment
assume cs:code,ds:data
call_c proc far
mov ax,data
mov ds,ax
mov es,ax
mov ax,stack ;load ss,sp
mov ss,ax
mov sp,offset toe
mov di,offset toem ;运算符栈栈顶
mov bx,offset toen ;数字栈栈顶
;MAIN PART OF THE PROGRAM GOES HERE:
mov ah,0ah ;输入表达式
mov dx,offset n
int 21h
push bx ;在表达式末尾加';'
mov bl,n+1
mov bh,0
mov express[bx],';'
pop bx
lea si,express
call compute ;计算表达式
mov dx,offset result ;输出提示信息
mov ah,9
int 21h
mov ax,[bx]
call binidec ;输出结果
mov ax,4c00h ;返回DOS
int 21h
call_c endp
;-----------------------------------------------------------
;function:对表达式中的元素判断并分类
;input: es:si the head of the express
;output:toen栈中bx所指向的为表达式的值
;Require:表达式以分号结尾
;-----------------------------------------------------------
compute proc near
;现场保护
;初始化
mpush 0 ;';'入运算符栈
mov dl,0
mov flag,0
mov negate,0
;-------------------------------
;是否结束的判断
rotate: cmp byte ptr [si],';'
jne not_semicolon
cmp brace,0 ;错误判断
jne error0_m
judge_error_flag:
cmp flag,2
jne error0_m
judge_stack_top_semicolon: ;遇到';'或')'时
cmp word ptr [di],0 ;是';'吗?
je exit_r
call account ;运算符栈栈顶不是分号时计算
jmp judge_stack_top_semicolon
exit_r: mpop ax ;读到表达式结尾并且运算符栈栈顶为分号时退出(';'出栈)
;现场恢复
ret
not_semicolon:
cmp byte ptr [si],')'
jne judge
dec brace
js error0_m
jmp judge_error_flag
error0_m:
jmp error0
;--------------------------------
;判断是否为数字
judge: mov al,byte ptr [si]
sub al,30h
cmp al,9
jbe number
jmp operator
number: call convey_number
jmp next
;--------------------------------
;判断是否为运算符
operator:
cmp byte ptr [si],'+'
jne judge_subtration
mov dh,1
mov cx,0101h
cmp flag,0
jne judge_error
mov flag,1
jmp next
judge_subtration:
cmp byte ptr [si],'-'
jne judge_multiplication
mov dh,1
mov cx,0102h
cmp flag,0
jne judge_error
mov negate,1
mov flag,1
jmp next
judge_multiplication:
cmp byte ptr [si],'*'
jne judge_division
mov dh,2
mov cx,0203h
jmp judge_error
judge_division:
cmp byte ptr [si],'/'
jne judge_bracket
mov dh,2
mov cx,0204h
judge_error:
cmp flag,2
jne error0
call calculate
jmp next
;-----------------------------------
;判断是否为'('
judge_bracket:
cmp byte ptr [si],'('
jne error0
cmp flag,1
ja error0
inc brace
inc si
call compute
mov flag,2
jmp next
;-----------------------------------
;出错信息
error0: mov ah,9
mov dx,offset mess0
int 21h
mov ax,4c00h
int 21h
;-----------------------------------
next: inc si
jmp rotate
compute endp
;-----------------------------------------------------------
;function:将一串ASCII码转换为一个二进制数
;input:Si指向表达式
; 用negate指示是否对转换好的数求补(negate=1则求补)
;output:将转换好的数入toen栈(数字栈)
;Require:已定义好数字栈,并用宏npush进行入栈操作
; 需调用decibin子程,请注意其要求
;-----------------------------------------------------------
convey_number proc near
push ax
call decibin
cmp negate,1
jne plus
neg ax
mov negate,0
plus: npush ax
mov flag,2
pop ax
ret
convey_number endp
;-----------------------------------------------------------
;function:将十进制数转换为二进制数
;input:Si指向表达式
;output:转换后的数放在AX中
;instruction:遇到非数字字符就认为该串数字结束
; 如数字过大导致溢出,则输出提示信息后程序结束
; 出错信息名为mess1,请在数据段中定义
;-----------------------------------------------------------
decibin proc near
push bx
push cx
push dx
mov bx,0
newchar:mov al,byte ptr [si]
sub al,30h
jl exit
cmp al,9d
jg exit
cbw
;digit is now in AX
;Multiply number in BX by 10 decimal
xchg ax,bx
mov cx,10d
imul cx
jno c1
jmp decibin_error1
c1: xchg ax,bx
;Add digit in AX to number in BX
add bx,ax
jno c2
jmp decibin_error1
c2: inc si
jmp newchar
exit: mov ax,bx ;将得数存入AX
dec si ;保证SI指向的是数字的最后一个
pop dx
pop cx
pop bx
ret
decibin_error1: ;出错处理
mov ah,9
mov dx,offset mess1
int 21h
mov ax,4c00h
int 21h
decibin endp
;-----------------------------------------------------------
;function:按优先级顺序判断并计算表达式
;input:cx:运算符编号
; dh:当前运算符的优先级
; dl:前一运算符的优先级
;require:已定义好运算符栈,并使用宏mpush,mpop进行初入栈操作
; 需调用account子程
;-----------------------------------------------------------
calculate proc near
judge_PRI:
cmp dh,dl ;比较当前运算符与前一运算符的优先级
jbe below_equal
mpush cx ;大于
mov dl,dh
mov flag,1
ret
below_equal:
jb below
call account ;等于
mpush cx
mov flag,1
ret
below: call account
mov dl,byte ptr [di+1]
jmp judge_PRI
calculate endp
;-----------------------------------------------------------
;function:根据运算符计算表达式
;-----------------------------------------------------------
account proc near
push cx
push dx
push si
npop cx ;弹出两个操作数
npop ax
mpop si ;弹出运算符
and si,0ffh ;将si的高字节清零
shl si,1
jmp table[si]
addition:
add ax,cx
jo error1
jmp account_exit
subtration:
sub ax,cx
jo error1
jmp account_exit
multiplication:
imul cx
jo error1
jmp account_exit
division:
cmp cx,0
je error2
cwd
idiv cx
jmp account_exit
error1: mov ah,9
mov dx,offset mess1
int 21h
mov ax,4c00h
int 21h
error2: mov ah,9
mov dx,offset mess2
int 21h
mov ax,4c00h
int 21h
account_exit:
npush ax
pop si
pop dx
pop cx
ret
account endp
;-----------------------------------------------------------
;function:将ax中的数转换为10进制数输出。
;input:ax
;output:none
;-----------------------------------------------------------
binidec proc near
push cx
push dx
push ax
push bx
;MAIN PART OF THE PROGRAM GOES HERE:
mov ch,0 ;CH为0则AX为正数,CH为1则Ax为负数
cmp ax,0
jge normal
neg ax
mov ch,1
normal: mov cl,0 ;计数器置零
mov bx,10
binidec_next:
mov dx,0
div bx
push dx
inc cl
cmp ax,0
jne binidec_next
cmp ch,1
jne print
mov ah,2
mov dl,'-'
int 21h
print: pop ax
mov dl,al
add dl,30h
mov ah,2
int 21h
dec cl
jne print
pop bx
pop ax
pop dx
pop cx
ret
binidec endp
code ends
end call_c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -