📄 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 <offset opStk>,01h
CreateStack <offset opnStk>,04h
;事先在操作符堆栈Push一个换行符作为运算结束标志
mov al,0ah
mov opBuffer,al
StackPush <offset opStk>,<offset opBuffer>
;打印输入数学表达式的提示语句
Puts <offset msg1>
;输入一个字符并保存到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 <offset opnStk>,<offset opnBuffer>
jmp @Begin
;第一种情况(操作符)
@Case1:
;求上一个操作符优先级别
StackTop <offset opStk>,<offset opBuffer>
mov al,opBuffer
call f
;求当前操作符优先级,并与上一操作符优先级别比较
call g
cmp al,ah
jb short @b
ja short @a
;两者相等,可能是一对括号或两个换行符(结束标记)
;前者,则读入一个字符,继续循环;后者循环结束
StackPop <offset opStk>,<offset opBuffer>
cmp opBuffer,0ah
jz short @End
GetChar
mov bl,al
jmp @Begin
@a:
;当前操作符优先级高。当前操作符压栈,读入字符,继续循环
mov opBuffer,bl
StackPush <offset opStk>,<offset opBuffer>
GetChar
mov bl,al
jmp @Begin
@b:
;当前操作符优先级低。取出上个操作符,并判断操作数栈是否小于2
;小于2出错;否则再取出两个操作数,用取出的操作符对它们进行运算
;运算结果压入操作数栈。继续循环
StackPop <offset opStk>,<offset opBuffer>
StackLength <offset opnStk>
cmp ax,0002h
jnl short @Skip
mov bl,opBuffer
jmp short Error
@Skip:
StackPop <offset opnStk>,<offset opnBuffer>
mov esi,opnBuffer
StackPop <offset opnStk>,<offset opnBuffer>
mov edi,opnBuffer
call Operation
mov opnBuffer,edi
StackPush <offset opnStk>,<offset opnBuffer>
jmp @Begin
@End:
;操作数栈是否正常
StackLength <offset opnStk>
cmp ax,0001h
jnz short Error
;打印运算结果
Puts <offset msg3>
StackPop <offset opnStk>,<offset opnBuffer>
PutLong <word ptr opnBuffer+02h>,<word ptr opnBuffer>
;
@Return:
ret
main endp
Error proc near
Puts <offset msg2>
PutChar bx
ClearStack <offset opnStk>
ClearStack <offset opStk>
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -