微机原理的大作业,用汇编写一个简单的计算器
实现中缀表达式计算
即(X–Y)*z/y+x=
可以输入负数,可以输入多位数
DATAS SEGMENT
STR6 DB 'please input a formula:' ,'$'
STR7 DB 'CONTINUE(Y/N)?$'
SIGN1 DW 0
SIGN2 DW 0
SIGN3 DB 1 ;记录上一个输入的字符是数字还是符号
sign4 DB 0 ;记录打印输出中的非零
WARN DB 'You are tring to divide 0!',0AH,0DH,'$'
num db 0 ;测试用
NUMBER DW 40 DUP(0)
OPERATOR DB '$'
DB 30 DUP(0)
ERROR DB 'parenthesis not paired! syntax error!$'
INPUTWARN DB 'ILLEGAL INPUT! ERROR$'
DATAS ENDS
STACKS SEGMENT STACK
S DB 256 DUP(?)
STACKS ENDS
SHOW MACRO STRING
push AX
PUSH DX
MOV DX,OFFSET STRING
MOV AH,09H
INT 21H
POP DX
POP AX
ENDM
char MACRO char ;调试用
push DX
push AX
MOV DL,char
add dl,30h
MOV AH,02H
INT 21H
pop AX
pop DX
ENDM
FQ MACRO ASCII,A,B
CMP AL,ASCII
JNE S&A
MOV CH,B
JMP S7
ENDM
HHHC MACRO
MOV AH,02H
MOV DL,0DH
INT 21H
MOV AH,02H
MOV DL,0AH
INT 21H
ENDM
CODES SEGMENT
;MAIN PROC FAR
ASSUME CS:CODES,DS:DATAS,ES:DATAS,SS:STACKS
;重写除0中断************************************************************************
INT0 PROC FAR
PUSH DX
PUSH AX
HHHC
SHOW WARN
HHHC
POP AX
POP DX
MOV AH,4CH
INT 21H
IRET
INT0 ENDP
START:
MOV AX,0
MOV ES,AX
MOV DI,0
MOV AX,OFFSET INT0
CLD
STOSW
MOV AX,SEG INT0
STOSW
;将程序地址写入中断向量表
MOV AX,DATAS
MOV DS,AX
MOV ES,AX
LEA DI,NUMBER
LEA SI,OPERATOR
START1:
MOV SIGN1,0
MOV SIGN2,0
MOV SIGN3,1
MOV SIGN4,0
MOV AX,0
MOV BX,0
MOV CX,0
MOV DX,0
HHHC
SHOW STR6
HHHC
INPUT:
MOV AH,01H
INT 21H
CMP AL,'='
JE LET0
CMP AL,28H
JB INPUTWRONG
CMP AL,39H
JA INPUTWRONG
CMP AL,2FH ;判断是否是符号,2F是最后一个符号除号
JBE LET1 ;转入符号处理
INC SIGN1 ;数字处理
MOV SIGN3,0
SUB AL,30H
MOV AH,0
XCHG AX,[DI] ;第一次放入的数字不乘十,之后放入的数字先乘十在加上新来的
MUL BX
MOV BX,10
ADD [DI],AX
JMP INPUT
INPUTWRONG:
HHHC
SHOW INPUTWARN
HHHC
JMP INPUT
LET0: ;=号转入
CMP WORD PTR SIGN2,0 ;如果不缺括号继续往下处理
JE LET1
JMP LET8
LET1:
CMP WORD PTR SIGN1,0 ;没有数字
JE LET2
ADD DI,2 ;已有数字而且检测到了运算符 数字堆栈后移一位
MOV WORD PTR SIGN1,0 ;清空标记
LET2:
CALL DYFQ
cmp ch,1
jz nex
mov SIGN3,1
jmp next
nex:
mov sign3,0
next:
CMP CH,5 ;是不是左括号
JNE LET3 ;不是下跳
INC WORD PTR SIGN2 ;是变更配对标志位
LET3:
CMP CH,1 ;是不是右括号
JNE LET4 ;
DEC WORD PTR SIGN2
LET4:
CMP BYTE PTR[SI],'$'
JE LET6
CMP CH,[SI] ;比较堆栈栈顶运算符优先级
JA LET6 ;若栈顶的小
CMP BYTE PTR [SI], 2 ;是不是左括号?
JNE LET5
DEC SI
JMP INPUT
LET5:
CMP [SI],6
JZ NEGATIVE
RETURN:
DEC SI ;吐出堆栈中运算符进行相应运算
MOV CL,[SI]
CALL YS
JMP LET4
NEGATIVE:
DEC SI
MOV [SI],3FH ;以问号作为求反操作码
inc SI
JMP RETURN
LET6: ;运算符堆栈空跳过来的或者要存放入栈
CMP CH,0 ;等号?
JE OUTPUT
CMP CH,1 ;右括号
JE INPUT ;右括号不保存
INC SI ;指向栈的开始,第一个是$
MOV [SI],AL ;放进堆栈 放的是符号
INC SI ;移位
CMP CH,5 ;是不是左括号
JNE LET7
MOV CH,2
LET7:
MOV [SI],CH ;SI里放得是优先级编码
JMP INPUT
LET8:
LEA DX,ERROR
MOV AH,09H
INT 21H
JMP EXIT
FQ MACRO ASCII,A,B
CMP AL,ASCII
JNE S&A
MOV CH,B
JMP S7
ENDM
DYFQ PROC
FQ 28H,1,5
S1: FQ 29H,2,1
S2: FQ 2AH,3,4
S3: FQ 2FH,4,4
S4: FQ 2BH,5,3
S5: FQ 3DH,6,0
S6:
CMP SIGN3,1
JZ NEWQ
FQ 2DH,7,3
NEWQ:
FQ 2DH,7,6
S7:
RET
DYFQ ENDP
OUTPUT:
SUB DI,2 ;初始是指向新数的
CMP WORD PTR[DI],0
JGE K1
NEG WORD PTR[DI]
MOV DL,'-'
MOV AH,2
INT 21H
and [di],7fh ;输出负数
K1: MOV BX,10000
MOV CX,5
K2: MOV AX,[DI]
CWD
DIV BX
MOV [DI],DX
CMP AL,0 ;如果是0就不打印出来
JNZ K3
CMP SIGN4,0
JNZ K3
CMP CX,1
JNZ DO2
MOV AH,02h
MOV DL,2EH
INT 21H
DO2:
CMP CX,1
JZ K3
JMP K4
K3:
MOV DL,AL
ADD DL,30H
MOV AH,02H
INT 21H
MOV sign4,1
K4: MOV AX,BX
MOV DX,0
MOV BX,10
DIV BX
MOV BX,AX ;基值除10
LOOP K2
HHHC
SHOW STR7
MOV AH,01H
INT 21H
CMP AL,'N'
JE EXIT
CMP AL,'n'
JE EXIT
MOV WORD PTR[DI+2],0
LEA DI,NUMBER
LEA SI,OPERATOR
JMP START1
EXIT:
MOV AH,4CH
INT 21H
YS PROC NEAR
PUSH AX
MOV AX,0
MOV BX,0
CMP CL,2AH
JNE CHU
SUB DI,2
XCHG BX,[DI]
SUB DI,2
XCHG AX,[DI]
IMUL BX ;有符号乘法
MOV [DI],AX
ADD DI,2
JMP FINISH
CHU:
CMP CL,2FH
JNE JIA
SUB DI,2
XCHG BX,[DI]
SUB DI,2
XCHG AX,[DI]
CWD
IDIV BX
MOV [DI],AX
ADD DI,2
JMP FINISH
JIA:
CMP CL,2BH
JNE JIAN
SUB DI,2
XCHG BX,[DI]
SUB DI,2
ADD [DI],BX
ADD DI,2
JMP FINISH
JIAN:
CMP CL,2DH
JNE NEGA
SUB DI,2
XCHG BX,[DI]
SUB DI,2
SUB [DI],BX
ADD DI,2
JMP FINISH
NEGA:
CMP CL,3FH
JNE FINISH
SUB DI,2
NEG word ptr [DI]
ADD DI,2
FINISH:
POP AX
RET
YS ENDP
CODES ENDS
END START