前言
1 仅仅支持两个操作数一个操作符的计算
2 输入为十进制, 输出为十六进制
参考代码
assume cs:code, ds:data, ss:stack
data segment
notice db 'please input a plus/subtract/multiply/divide expression : $ ' ; notice information
buffer db 16 ; the buffer to saved the information user inputed, and result show information
db 0
db 32 dup (0), ' $ '
operand dw 4 dup (0) ; save the operand and operator and calcute result
; result db 32 dup (0)
errInfo db 0aH, 0dH, 'have no operator.... $ ' ; save the error information
tmp dw 2 dup (0) ; the temp memory for save offset
data ends
stack segment
db 128 dup (0)
stack ends
code segment
start:
mov ax, data
mov ds, ax
mov ax, stack
mov ss, ax ; initilization ds, ss
lea dx, notice
mov ah, 9
int 21H ; output notice information
lea dx, buffer
mov ah, 10
int 21H ; let user to input
mov cl, buffer[1]
mov ch, 0 ; get the length of user inputed
call getOperator ; get operator, and offset saved in si, and save it into 'operand[1]'
; call getNumValue
call getOperand ; get the operand, save it into 'operand', 'operand[2]'
call calcuteIt ; to calcute the expression
call putResultIntoMemory ; put the information into specified memory
lea dx, buffer+2 ; show the result information
mov ah, 9
int 21H
mov ax, 4c00H ; return to cmd
int 21H
; getNumValue proc near
; getNumValueLoop1:
; loop getNumValueLoop1
; getNumValue endp
putResultIntoMemory proc near ; put the result into memory for show
push di
push bx
mov di, cx
add di, 2
mov buffer[di], '='
mov bx, operand[6]
call calcOneWord
pop bx
pop di
ret
putResultIntoMemory endp
calcHalfByte proc near ; calc the bl [----just judge lower four bit----]' s corresponding ascii code, save in bl
; push bx ; bl record the data[need to be transfer]
push cx ; record the offset to save in exp data segment
cmp bl, 9
ja abc
; bl not bigger than 9
; mov [exp+cx], bl+48 ; 1 ~ 8
add bl, 48
jmp calcHalfByteEnd
abc: ; bl bigger than 9
; mov [exp+cx], bl+87 ; A ~ F
add bl, 87
calcHalfByteEnd:
pop cx
ret
calcHalfByte endp
calcHalfWord proc ; to calcute two hexadecimal number, number saved in bl, need to push two offset relative exp flag to save data
push bx
push di
push dx
push cx
; add sp, 4 ; mov stack pointer to save data offset, why there need just add 2 bit ? it just push ip in stack ?
mov dx, bx
mov cl, 4 ; calc the upper 4 bit
shr bl, cl
call calcHalfByte
; pop di
mov di, ds:[tmp] ; the segment of tmp must match the left value[cx], use dw to define data
mov ds:[buffer+di], bl
mov bx, dx ; calc the lower 5 bit
and bl, 15
call calcHalfByte
; pop di
mov di, ds:[tmp+2]
mov ds:[buffer+di], bl
; sub sp, 6 ; mov stack pointer to the real stack top
; why the value in stack changed ??? --2014.07.25
pop cx
pop dx
pop di
pop bx
ret
calcHalfWord endp
calcOneWord proc near ; to calcute two hexadecimal number, number saved in 'bx', 'di' saved the memory offset,
push dx
push di
mov dx, bx
mov cl, 8 ; calc the upper 8 bit of bx
shr bx, cl
inc di
mov ds:[tmp], di
inc di
mov ds:[tmp+2], di
call calcHalfWord
mov bx, dx ; calc the lower 8 bit of bx
mov bh, 0
inc di
mov ds:[tmp], di
inc di
mov ds:[tmp+2], di
call calcHalfWord
pop di
pop dx
ret
calcOneWord endp
calcuteIt proc near ; to calcute the value of expression, and save it to specified memory
push bx
push ax
push dx
mov bx, operand[2]
cmp bx, 1
jz opePlus2
cmp bx, 2
jz opeSub2
cmp bx, 3
jz opeMul2
cmp bx, 4
jz opeDiv2
jmp calcuteItEnd
opePlus2:
mov ax, ds:[operand]
add ax, operand[4]
mov operand[6], ax
jmp calcuteItEnd
opeSub2:
mov ax, ds:[operand]
sub ax, operand[4]
mov operand[6], ax
jmp calcuteItEnd
opeMul2:
mov ax, ds:[operand]
mul operand[4]
mov operand[6], ax ; for simple, ignore dx
jmp calcuteItEnd
opeDiv2:
mov ax, ds:[operand]
div operand[4]
mov operand[6], ax ;
jmp calcuteItEnd
calcuteItEnd:
pop dx
pop ax
pop bx
ret
calcuteIt endp
getOperand proc near ; to get two operand, and put them into specified meomry
push di
push si
push dx
push cx
cmp operand[1], 0
jz getOperandOnError
; mov cx, si-2 ; error
; mov di, si-1
mov cx, si
sub cx, 2
mov di, si
dec di
mov al, 1
mov dx, 0
call getOperandValue
mov ds:[operand], dx
pop cx
push cx
; mov cx, dx+1-si ; error
; mov di, dx+1
sub cx, si
inc cx
mov di, cx
add di, si
mov al, 1
mov dx, 0
call getOperandValue
mov ds:[operand+4], dx
jmp getOperandEnd
getOperandOnError: ; address flag can't duplicated with others flag
call onError
getOperandEnd:
pop cx
pop dx
pop si
pop di
ret
getOperand endp
getOperandValue proc near ; get operand NumberValue by the number string in memory 1 2 3 -> 123
push di
push ax
getOperandValueLoop1:
mov ah, buffer[di]
call getNumValue
push ax
mul ah
add dx, ax
pop ax
mov ah, 10
mul ah
dec di
loop getOperandValueLoop1
pop ax
pop di
ret
getOperandValue endp
getNumValue proc near ; get NumberValue by ascii
cmp ah, 48
jae numFlag1
jmp getNumValueEnd
numFlag1:
cmp ah, 57
jbe numFlag2
jmp alphaFlag1
numFlag2:
sub ah, 48
jmp getNumValueEnd
alphaFlag1:
cmp ah, 97
jae alphaFlag2
jmp getNumValueEnd
alphaFlag2:
cmp ah, 102
ja getNumValueEnd
sub aH, 87
getNumValueEnd:
ret
getNumValue endp
onError proc near ; deal while error happened
push dx
push ax
lea dx, errInfo
mov ah, 9
int 21H
pop ax
pop dx
ret
onError endp
getOperator proc near ; get the operator in expression, the offset of operator saved in 'si'
push cx
push bx
mov si, 2
getOperatorLoop1:
mov bl, buffer[si]
call ifIsOperator
jc getOperatorEnd
inc si
loop getOperatorLoop1
getOperatorEnd:
pop bx
pop cx
ret
getOperator endp
ifIsOperator proc near ; to judge if 'bl' is a operator
cmp bl, 43
jz opePlus
cmp bl, 45
jz opeSub
cmp bl, 42
jz opeMul
cmp bl, 47
jz opeDiv
jmp ifIsOperatorEnd
opePlus:
mov operand[2], 1
jmp ifIsOperatorBeforeEnd
opeSub:
mov operand[2], 2
jmp ifIsOperatorBeforeEnd
opeMul:
mov operand[2], 3
jmp ifIsOperatorBeforeEnd
opeDiv:
mov operand[2], 4
jmp ifIsOperatorBeforeEnd
ifIsOperatorBeforeEnd:
stc
ifIsOperatorEnd:
ret
ifIsOperator endp
code ends
end start
; made by 970655147 2014.07.27
效果截图 :