www.pudn.com > Demo_asm_80x86.rar > Arith.asm


;****************************************************** 
;* 文件名:Arith.asm 
;* 创建日期:2001.6.29 
;* 作者:陈文尧 
;* 功能:计算数学表达式,比如:12*(1+2*4)^(30-5^2)/21 
;* 备注:1、本程序由本人大学时代的C++程序改编而来, 
;*         目的是用来测试“未来汇编”的堆栈库函数; 
;*      2、本程序可以编译成.com文件或.exe文件; 
;*      3、编译本程序必需使用“未来汇编”. 
;*      4、由于本程序使用了栈的库函数,所以必须释放一些 
;*         多余的内存给他使用,这只要在<汇编专家>里加上 
;*         "程序中释放多余内存"就会添上ModifyMemory宏, 
;*         该宏有一个可选的参数,这里就不细说。 
;****************************************************** 
include system.inc 
include stdio.inc 
include stack.inc 
;****************************************************** 
;* 以下代码由汇编专家产生,不要随便修改 
;****************************************************** 
.CODE 
	ifdef __COM__ 
		org	100h 
	endif 
@@Start: 
;------------------------------------------------------ 
; 初始化数据段 
;------------------------------------------------------ 
	InitDS	cs 
;------------------------------------------------------ 
; 释放多余内存 
;------------------------------------------------------ 
	ModifyMemory	;xxx 
;------------------------------------------------------ 
; 调用主函数 
;------------------------------------------------------ 
	call	main 
;------------------------------------------------------ 
; 正常返回DOS 
;------------------------------------------------------ 
@@Exit: 
	ReturnDos 
 
;++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
;+ 主函数,加入实现程序功能的代码 
;++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
main	proc 
      ;创建空堆栈:opStk--操作符堆栈,每个结点长度为1; 
      ;            opnStk--操作数堆栈,每个结点长度为4 
	CreateStack	,01h 
	CreateStack	,04h 
 
	 
	;事先在操作符堆栈Push一个换行符作为运算结束标志 
	mov		al,0ah 
	mov		opBuffer,al 
	StackPush	, 
	 
	;打印输入数学表达式的提示语句 
	Puts	 
	 
	;输入一个字符并保存到bl 
	;“未来汇编”库函数与C/C++函数的pascal方式有点类似: 
	;   1、除ax、dx、cx和es以外的寄存器(在函数里值改变)事先给予保存 
	;   2、返回值一个字节在al,两个在ax,四个在eax或dx:ax 
	;   3、参数从左到右压栈,栈由函数填平 
	;   4、出错(这对部分函数来说),则cf=1;否则cf=0 
	GetChar 
	mov		bl,al 
	 
@Begin: 
	;对输入的字符(在bl)进行判断,结果在al 
	call		Judge 
	;判断结果是1(操作符),则跳到第一种情况进行处理 
	cmp		al,01h 
	jz		short @Case1 
	;判断结果是2(数字),则跳到第二种情况进行处理 
	cmp		al,02h 
	jz		short @Case2 
	;判断结果是3(空格),则跳到第三种情况进行处理 
	cmp		al,03h 
	jz		short @Case3 
	;其它则出错 
	jmp		Error 
	 
	;第三种情况(空格),略过空格,重新输入一个字符,继续循环 
@Case3: 
      GetChar 
      mov		bl,al 
      jmp		@Begin 
       
	;第二种情况(数字) 
@Case2: 
	sub		esi,esi 
@Case2@Begin: 
      ;edi=esi*10 
	imul		edi,esi,0ah 
	;esi=读入的数 
	mov		esi,ebx 
	and		esi,000000ffh 
	sub		esi,'0' 
	;esi+=edi 
	add		esi,edi 
	;读入字符,判断是否仍是数字 
	GetChar 
	mov		bl,al 
	call		Judge 
	cmp		al,02h 
	;是数字,继续算数 
	jz		@Case2@Begin 
	;不是数字,则把得到的数压入操作数栈,继续循环 
      mov		opnBuffer,esi 
      StackPush	, 
      jmp		@Begin 
       
      ;第一种情况(操作符) 
@Case1: 
      ;求上一个操作符优先级别 
      StackTop	, 
      mov		al,opBuffer 
      call		f 
      ;求当前操作符优先级,并与上一操作符优先级别比较 
      call		g 
      cmp		al,ah 
      jb		short @b 
      ja		short @a 
      ;两者相等,可能是一对括号或两个换行符(结束标记) 
      ;前者,则读入一个字符,继续循环;后者循环结束 
      StackPop	, 
      cmp		opBuffer,0ah 
      jz		short @End 
      GetChar 
      mov		bl,al 
      jmp		@Begin       
@a: 
      ;当前操作符优先级高。当前操作符压栈,读入字符,继续循环 
      mov		opBuffer,bl 
      StackPush	, 
      GetChar 
      mov		bl,al 
      jmp		@Begin 
@b: 
      ;当前操作符优先级低。取出上个操作符,并判断操作数栈是否小于2 
      ;小于2出错;否则再取出两个操作数,用取出的操作符对它们进行运算 
      ;运算结果压入操作数栈。继续循环 
      StackPop	, 
      StackLength	 
      cmp		ax,0002h 
      jnl		short @Skip 
      mov		bl,opBuffer 
      jmp		short Error 
@Skip: 
      StackPop	, 
      mov		esi,opnBuffer 
      StackPop	, 
      mov		edi,opnBuffer 
      call		Operation 
      mov		opnBuffer,edi 
      StackPush	, 
      jmp		@Begin 
@End: 
      ;操作数栈是否正常 
      StackLength	 
      cmp		ax,0001h 
      jnz		short Error 
      ;打印运算结果 
      Puts		 
      StackPop	, 
      PutLong	, 
	; 
@Return: 
	ret 
main	endp 
 
Error proc near 
      Puts		 
      PutChar	bx 
      ClearStack	 
      ClearStack	 
      mov		ax,4c01h 
      int		21h 
Error endp 
 
;判断字符:0、非法字符;1、运算符号;2、数字;3、空格 
Judge proc near 
      cmp	bl,'+' 
      jz	short @Judge1 
      cmp	bl,'-' 
      jz	short @Judge1 
      cmp	bl,'*' 
      jz	short @Judge1 
      cmp	bl,'/' 
      jz	short @Judge1 
      cmp	bl,'^' 
      jz	short @Judge1 
      cmp	bl,0ah 
      jz	short @Judge1 
      cmp	bl,'(' 
      jz	short @Judge1 
      cmp	bl,')' 
      jz	short @Judge1 
      cmp	bl,'0' 
      jb	short @NextJudge 
      cmp	bl,'9' 
      ja	short @NextJudge 
      mov	al,02h 
      ret 
@NextJudge: 
      cmp	bl,' ' 
      jz	short @Judge3 
      cmp	bl,09h 
      jz	short @Judge3 
      mov	al,00h 
      ret 
@Judge1: 
      mov	al,01h 
      ret 
@Judge3: 
      mov	al,03h 
      ret 
Judge endp 
 
;f、g函数:判断操作符的优先级别 
f proc near 
  cmp		al,'+' 
  jz		short @f4 
  cmp		al,'-' 
  jz		short @f4 
  cmp		al,'*' 
  jz		short @f6 
  cmp		al,'/' 
  jz		short @f6 
  cmp		al,'(' 
  jz		short @f2 
  cmp		al,')' 
  jz		short @f9 
  cmp		al,'^' 
  jz		short @f6 
  mov		ah,01h 
  ret 
@f2: 
  mov		ah,02h 
  ret 
@f4: 
  mov		ah,04h 
  ret 
@f6: 
  mov		ah,06h 
  ret 
@f9: 
  mov		ah,09h 
  ret 
f endp 
 
g proc near 
  cmp		bl,'+' 
  jz		short @g3 
  cmp		bl,'-' 
  jz		short @g3 
  cmp		bl,'*' 
  jz		short @g5 
  cmp		bl,'/' 
  jz		short @g5 
  cmp		bl,'(' 
  jz		short @g8 
  cmp		bl,')' 
  jz		short @g2 
  cmp		bl,'^' 
  jz		short @g8 
  mov		al,01h 
  ret 
@g2: 
  mov		al,02h 
  ret 
@g3: 
  mov		al,03h 
  ret 
@g5: 
  mov		al,05h 
  ret 
@g8: 
  mov		al,08h 
  ret 
g endp 
 
;进行运算:操作符opBuffer;第一操作数edi;第二操作数esi;结果edi 
Operation proc near 
          mov	al,opBuffer 
          cmp	al,'+' 
          jz	short @Add 
          cmp	al,'-' 
          jz	short @Sub 
          cmp	al,'*' 
          jz	short @Mul 
          cmp	al,'/' 
          jz	short @Div 
          cmp	al,'^' 
          jz	short @Pow 
          mov	bl,al 
          jmp	Error 
@Pow: 
          mov	ecx,esi 
          sub	eax,eax 
          inc	eax 
          jcxz	short @Skip2 
@PowNext: 
          imul	edi 
          loop	@PowNext 
@Skip2: 
          mov	edi,eax 
          ret 
@Add: 
          add	edi,esi 
          ret 
@Sub: 
          sub	edi,esi 
          ret 
@Mul: 
          mov	eax,edi 
          imul	esi 
          mov	edi,eax 
          ret 
@Div: 
          mov	eax,edi 
          sub	edx,edx 
          idiv	esi 
          mov	edi,eax 
          ret 
Operation endp 
 
msg1      db '请输入数学表达式:',00h 
msg2      db '输入错误:',00h 
msg3      db '计算结果:',00h 
opBuffer  db ? 
opnBuffer dd ? 
opStk	    FSTACK	<> 
opnStk    FSTACK	<> 
;****************************************************** 
;* 标志程序结束并指定程序入口 
;****************************************************** 
	end	@@Start