.model small
.stack 100h
.data

BeginM db "Enter Expression #+-*/#=",10,13,": $"
OpenM db 10,13,"Simple Calculator by John Reed",10,13,"Press Esc to exit",10,13,"$"
Err1M db 10,13,"You must enter numbers",10,13,": $"
Err2M db 10,13,"Invalid Operator, use +-*/",10,13,": $"
FBufferM db "..........$"
LBufferM db "..........$"
AnswerM  db "          $"
.code
;Flags in CL [#1,#1 has int, operator,#2,#2 has int,Opbit1,Opbit2,Opbit3]
start:
  mov ax,@data
  mov ds,ax
NewEx:
  mov cl,00				;use for flags
  mov dx,offset BeginM			;instruction string
  mov ah,09h				;dos print
  int 21h				;print instruction string
  mov dx,0000h
InputEx:
  mov ah,01h				;input one character
  int 21h				;into al
  mov ch,00100000b			;check if first number and operator has been entered
  and ch,cl				;CH contains results
  jz PutIn1				;#1 is empty
  jmp PutIn2
IReturn:
  jmp InputEx   
OutPutEx:
 
  ;mov dx,offset FBufferM
  ;mov ah,09h
  ;int 21h
  ;mov dx,offset LBufferM
  ;int 21h

  mov dx,0000h
  mov bx,offset FBufferM
  call DecToHex
  push dx				;save #1 on stack
  mov bx,offset LBufferM
  call DecToHex
  push dx				;save #2 on stack
  
  mov bl,00000100b			;bitmask for adition
  and bl,cl				;check if + operator
  jnz ADDM
  mov bl,00000001b			;bitmask for multiplication
  and bl,cl				;check if * operator
  jnz MULM
  mov bl,00000010b			;bitmask for subtraction
  and bl,cl				;check if - operator
  jnz SUBM
  mov bl,00000111b			;bitmask fo division
  and bl,cl
  jz DIVM
MULM:
  mov dx,0000h
  mov bx,offset FBufferM		;check if first negative
  mov al,[bx]
  cmp al,"-"
  jne MULNext
  mov dl,0FFh
  MULNext:
  mov bx,offset LBufferM		;check if second negative
  mov al,[bx]
  cmp al,"-"
  jne MULNext2
  mov dh,0FFh
  MULNext2:
  sub dh,dl				;check if both negative
  jz MULNext3
  mov dl,2dh				;print - sign
  mov ah,02h
  int 21h
  MULNext3:
  pop bx				;get second num off stack
  pop ax				;get first num off stack
  mul bx				;multiply them
  push ax
  mov ax,dx
  ;call HexToDec
  pop ax
  call HexToDec
  jmp MEND
DIVM:
  mov dx,0000h
  mov bx,offset FBufferM		;check if first negative
  mov al,[bx]
  cmp al,"-"
  jne DIVNext
  mov dl,0FFh
  DIVNext:
  mov bx,offset LBufferM		;check if second negative
  mov al,[bx]
  cmp al,"-"
  jne DIVNext2
  mov dh,0FFh
  DIVNext2:
  sub dh,dl				;check if both negative
  jz DIVNext3
  mov dl,2dh				;print - sign
  mov ah,02h
  int 21h
  DIVNext3:
  pop bx				;get second num off stack
  pop ax				;get first num off stack
  mov dx,0000h				;
  div bx				;divide them
  call HexToDec
  cmp dx,0000h				;check for remainder
  je MEND
  push bx
  push dx
  mov ah,02h
  mov dl,"."
  int 21h
  pop dx
 ;call IDebug
  mov ax,dx
  mov bx,0Ah
  mul bx				;multiply remainder by base 16
  pop bx
  mov dx,0000h
  div bx				;divide by original num
  call HexToDec
  jmp MEND
ADDM:
  mov bx,offset FBufferM
  mov al,[bx]
  cmp al,"-"				;check if first num negative
  je ADFNeg
  mov bx,offset LBufferM
  mov al,[bx]
  cmp al,"-"				;check if only second num negative
  je ADOSNeg
  pop ax				;get second num
  pop dx				;get first num
  add ax,dx				;both positive
  call HexToDec
   jmp MEND
 ADOSNeg:				;second num is negative
  pop ax				;get second num
  pop dx				;get first num
  cmp ax,dx
  jg ADSub1
  sub dx,ax				;first num greater
  mov ax,dx				;answer will be positive
  call HexToDec
  jmp MEND
 ADSub1:
  push ax
  push dx
  mov dl,"-"
  mov ah,02h
  int 21h				;print - sign
  pop dx
  pop ax
  sub ax,dx
  call HexToDec
  jmp MEND
 ADFNeg:
  mov bx,offset LBufferM
  mov al,[bx]
  cmp al,"-"				;check if both negative
  je ADSNeg
  pop ax				;get second num
  pop dx				;get first num
  cmp dx,ax				;only sec num is negative
  jg ADSub2				;first num is greater
  sub ax,dx				;answer will be positive
  call HexToDec				;when first num less
  jmp MEND
 ADSub2:
  push ax
  push dx
  mov dl,"-"
  mov ah,02h
  int 21h				;print - sign
  pop dx
  pop ax
  sub dx,ax				;subtract second from first
  mov ax,dx
  call HexToDec
  jmp MEND
 ADSNeg:				;both negative
  mov dl,"-"
  mov ah,02h
  int 21h				;print - sign
  pop ax				;get second num
  pop dx				;get first num
  add ax,dx
  call HexToDec
  jmp MEND

SUBM:
  mov bx,offset FBufferM
  mov al,[bx]
  cmp al,"-"				;check if first num negative
  je SBFNeg
  mov bx,offset LBufferM
  mov al,[bx]
  cmp al,"-"				;check if only second num negative
  je SBOSNeg
					;both positive
  pop ax				;get second num
  pop dx				;get first num
  cmp ax,dx
  jg SBSub1
  sub dx,ax				;first num greater
  mov ax,dx				;answer will be positive
  call HexToDec
  jmp MEND
 SBSub1:
  push ax
  push dx
  mov dl,"-"
  mov ah,02h
  int 21h				;print - sign
  pop dx
  pop ax
  sub ax,dx
  call HexToDec
  jmp MEND
 SBOSNeg:				;second num is negative
  pop ax				;get second num
  pop dx				;get first num
  add ax,dx
  call HexToDec
  jmp MEND
 SBFNeg:
  mov bx,offset LBufferM
  mov al,[bx]
  cmp al,"-"				;check if both negative
  je SBSNeg
  mov dl,"-"				;first num negative
  mov ah,02h
  int 21h				;print - sign
  pop ax				;get second num
  pop dx				;get first num
  add ax,dx
  call HexToDec
  jmp MEND


  SBSNeg:				;both negative
  pop ax				;get second num
  pop dx				;get first num
  cmp dx,ax				;only sec num is negative
  jg SBSub2				;first num is greater
  sub ax,dx				;answer will be positive
  call HexToDec				;when first num less
  jmp MEND
 SBSub2:
  push ax
  push dx
  mov dl,"-"
  mov ah,02h
  int 21h				;print - sign
  pop dx
  pop ax
  sub dx,ax				;subtract second from first
  mov ax,dx
  call HexToDec
  jmp MEND

MEND:
  mov ax,4c00h
  int 21h


PutIn1:
  mov ch,10000000b			;check if first entry has been done
  and ch,cl
  jnz SecCheck
  cmp al,"-"
  je SecEntry
 SecCheck:
  mov bl,al
  call IsNumeric
  cmp bl,00h
  je In1Err				;entry is not a number
  or cl,01000000b			;there is a number in first entry
 SecEntry:
  or cl,10000000b			;first entry has started
  mov bx,offset FBufferM
  add bx,dx
  inc dx
  mov [bx],al
  jmp IReturn
 In1Err:
  mov ch,01000000b
  and ch,cl				;if we have a number in #1
  jnz FindOp
  mov dx,offset Err1M			;set error message
  mov ah,09h				;do dos print
  int 21h				;do dos call
  jmp NewEx				;start over
 FindOp:
  and cl,11111000b
  cmp al,"+"
  je OpPlus
  cmp al,"-"
  je OpMinus
  cmp al,"*"
  je OpTimes
  cmp al,"/"
  je OpDiv
  mov dx,offset Err2M			;set error message
  mov ah,09h				;do dos print
  int 21h				;do dos call
  jmp NewEx				;start over
 OpPlus:
  or  cl,00000100b			;set + operator
  or  cl,00100000b			;operator has been entered
  mov dx,0000h				;reinitialize counter
  jmp IReturn
 OpMinus:
  or  cl,00000010b			;set - operator
  or  cl,00100000b			;operator has been entered
  mov dx,0000h				;reinitialize counter
  jmp IReturn
 OpTimes:
  or  cl,00000001b			;set * operator
  or  cl,00100000b			;operator has been entered
  mov dx,0000h				;reinitialize counter
  jmp IReturn
 OpDiv:
  and  cl,11111000b			;set / operator
  or  cl,00100000b			;operator has been entered
  mov dx,0000h				;reinitialize counter
  jmp IReturn


PutIn2:
  mov ch,00010000b			;check if first entry has been done
  and ch,cl
  jnz SecCheck2
  cmp al,"-"
  je SecEntry2
 SecCheck2:
  mov bl,al
  call IsNumeric
  cmp bl,00h
  je In2Err				;entry is not a number
  or cl,01000000b			;there is a number in first entry
 SecEntry2:
  or cl,00010000b			;first entry has started
  mov bx,offset LBufferM
  add bx,dx
  inc dx
  mov [bx],al
  jmp IReturn
 In2Err:
  cmp al,"="
  je OutPutEx
  mov dx,offset Err1M			;set error message
  mov ah,09h				;do dos print
  int 21h				;do dos call
  jmp NewEx				;start over

;convert ascii decimal in mem to hex
;offset of value in memory in bx
;return value in dx
DecToHex:
push ax
push cx
mov dx,0000h
mov cx,0000h				;use cl for dec place
mov ax,0006h				;number of bytes to check
add bx,ax				;go to end of buffer
dec bx
DTHStart:
;call IDebug
mov ch,[bx]				;get first value
cmp ch,"."				;get rid of spaces
jne DTHIsNum
dec bx					;go to next value
dec ax
jmp DTHStart				;read in next value
DTHIsNum:
cmp ch,"-"				;check if - at end
je NCheck
cmp cl,00h				;check if in 1s place
je DTHOnes
cmp cl,01h
je DTHTens
cmp cl,02h
je DTHHuns
cmp cl,03h
je DTHThou
cmp cl,04h
je DTHTenT
jmp NCheck

DTHOnes:
mov dl,ch				;move ascii value into dx
sub dx,30h				;subtract 30 to get hex value
inc cl					;goto 10s place
jmp NCheck				;check next character

DTHTens:
push bx
push ax
mov bl,0Ah				;mul hex base by a
mov al,ch
sub al,30h				;convert ascii to hex base
mul bl					;multiply
add dx,ax				;add to overall total
inc cl					;goto 100s place
pop ax
pop bx
jmp NCheck

DTHHuns:
push bx
push ax
mov bl,64h				;mul hex base by 64
mov al,ch
sub al,30h				;convert ascii to hex base
mul bl					;multiply
add dx,ax				;add to overall total
inc cl					;goto 1000s place
pop ax
pop bx
jmp NCheck

DTHThou:
push bx
push ax
mov bx,3e8h				;mul hex base by a
mov al,ch
sub al,30h				;convert ascii to hex base
push dx
mul bx					;multiply
pop dx
add dx,ax				;add to overall total
inc cl					;goto 100s place
pop ax
pop bx
jmp NCheck

DTHTenT:
push bx
push ax
mov bx,2710h				;mul hex base by a
mov al,ch
sub al,30h				;convert ascii to hex base
push dx
mul bx					;multiply
pop dx
add dx,ax				;add to overall total
inc cl					;goto 100s place
pop ax
pop bx
jmp NCheck

NCheck:
dec bx
dec ax
jz DRet
jmp DTHStart
DRet:
;call IDebug
pop cx
pop ax
ret

;convert hex numbers in register and print to screen
;number to convert in ax
HexToDec:
push dx
mov dx,0000h
push cx
mov cx,0000h
push ax
mov bx,2710h
div bx					;check 10k place
cmp ax,0000h				;check if there is a digit there
je HTD1k

push ax					;save ax
mov dx,ax
add dx,30h				;convert hex to ascii
mov ah,02h
int 21h					;print ascii
pop ax

mov bx,2710h
mul bx
mov bx,ax
pop ax
sub ax,bx				;subtract 10ks to get remainder
push ax
mov cl,0FFh

HTD1K:
pop ax
push ax
mov bx,3e8h
mov dx,0000h
div bx
cmp cl,0FFh
je HTD1kPrint
cmp ax,0000h
je HTD100

HTD1kPrint:
push ax					;save ax
mov dx,ax
add dx,30h				;convert hex to ascii
mov ah,02h
int 21h					;print ascii
pop ax

mov bx,3e8h
mul bx
mov bx,ax
pop ax
sub ax,bx				;subtract 1ks to get remainder
push ax
mov cl,0FFh

HTD100:
pop ax
push ax
mov bx,64h
mov dx,0000h
div bx
cmp cl,0FFh
je HTD100Print
cmp ax,0000h
je HTD10

HTD100Print:
push ax					;save ax
mov dx,ax
add dx,30h				;convert hex to ascii
mov ah,02h
int 21h					;print ascii
pop ax

mov bx,64h
mul bx
mov bx,ax
pop ax
sub ax,bx				;subtract 1ks to get remainder
push ax
mov cl,0FFh

HTD10:
pop ax
push ax
mov bx,0ah
mov dx,0000h
div bx
cmp cl,0FFh
je HTD10Print
cmp ax,0000h
je HTD1

HTD10Print:
push ax					;save ax
mov dx,ax
add dx,30h				;convert hex to ascii
mov ah,02h
int 21h					;print ascii
pop ax

mov bx,0ah
mul bx
mov bx,ax
pop ax
sub ax,bx				;subtract 1ks to get remainder
push ax
mov cl,0FFh

HTD1:
pop ax
add ax,30h
mov dx,ax
mov ah,02h
int 21h
pop cx
pop dx
ret

;character to check in bl
;result is put in bl unchanged if number 00 if not
IsNumeric:
  mov bh,2Fh				;start at character before 0
IsNTest:
  inc bh				;go to next character
  cmp bh,bl				;check if numeric
  je IsNTrue				;if it is no change and return
  cmp bh,3Ah				;if we are past 9
  je IsNFalse				;character is not number return 00
  jmp IsNTest
IsNTrue:
  ret
IsNFalse:
  mov bl,00h
  ret

;Debug routine
IDebug:
push ax
push bx
push cx
push dx
pushf
push dx
push cx
mov cx,ax
mov ah,02h
mov dl,10
int 21h
mov dl,13
int 21h
mov dl,ch
int 21h
mov dl,cl
int 21h
mov dl,10
;int 21h
mov dl,13
;int 21h
mov dl,bh
int 21h
mov dl,bl
int 21h
mov dl,10
;int 21h
mov dl,13
;int 21h
pop cx
mov dl,ch
int 21h
mov dl,cl
int 21h
mov dl,10
;int 21h
mov dl,13
;int 21h
pop dx
mov cx,dx
mov dl,ch
int 21h
mov dl,cl
int 21h

popf
pop dx
pop cx
pop bx
pop ax
ret
end start