⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 express.asm

📁 算式计算 1、摘要:使用堆栈计算由加、减、乘、除、括号组成的表达式。 2、参考资料: IBM-PC汇编语言程序设计(第二版)
💻 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 + -