Search code examples
assemblyexpressionx86-16tasmdosbox

Program solving expression in assembly


I have a problem with my simple program in assembly. I'm using DOSBox and TASM. The problem is that the operand types don't match in lines 76, 78, and 80. This is after multiplication. I tried to make some changes by using a different variable size.

; --------------------------------------------
; Equation=(a+c*b)/d-2*c,
; --------------------------------------------
.model small
.stack 100h
.data
        a       db 0                           
        b       db 0
        c       db 0
        d       db 0
        result1 db ?
        result2 db ?
       
 
       
        message1 db "Equation: (a+c*b)/d-2*c   a=$"
        message2 db "b=$"
        message3 db "c=$"
        message4 db "d=$"
        message5 db "Result=$"
.code
 
start:  mov ax,@data
                mov ds,ax                      

                mov ax, seg message1   ;get a and save to a variable
                mov ds,ax      
                mov dx,offset message1
                mov ah, 9h
                int 21h
                mov ah, 1h
                int 21h
                sub al,30h    ;converting to real number
                mov a,al
               
                mov ax, seg message2 ;get b and save to a variable
                mov ds,ax      
                mov dx,offset message2
                mov ah, 9h
                int 21h
                mov ah, 1h
                int 21h
                sub al,30h    ;converting to real number
                mov b,al
               
               
                mov ax, seg message3    ;get c and save to a variable
                mov ds,ax      
                mov dx,offset message3
                mov ah, 9h
                int 21h
                mov ah, 1h
                int 21h
                sub al,30h    ;converting to real number
                mov c,al
               
            
                mov ax, seg message4   ;get d and save to a variable
                mov ds,ax      
                mov dx,offset message4
                mov ah, 9h
                int 21h
                mov ah, 1h
                int 21h
                sub al,30h   ;converting to real number
                mov d,al
               
               
                mov al,b         ; (a+c*b) ------------------------error
                mul c                          
                add ax,a       ; ------------------------error
       
                push ax     ;save current ax
       
                mov ax,c     ;d-2*c------------------------error
                shl ax,2
                sub d,ax
               
               
                pop bx     ;get previous ax  to bx
               
                div bx     ; div ax:bx
               
                mov result1,al
                mov result2,ah
       
                add result1,30h   ;converting to string
                add result2,30h    ;converting to string
               
                mov al,result1
                mov bl,result2
               
                mov ax, seg message5
                mov ds,ax      
                mov dx,offset message5
                mov ah, 9h
                int 21h
                mov al,result1
                mov bl,result2
                mov dl, al
                mov ah , 2h
                int 21h
                mov dl, bl
                mov ah , 2h
                int 21h
               
                mov ax,4C00h           
                int 21h
 
end             start

Solution

  • Your program is almost good, you only have some issues with operand sizes, which is normal. So I took your code and made some little changes, those changes are commented and pointed by arrows (<========) and they are :

    • Fixed the operand size problem. I still use DB because I noticed you are capturing the numbers as single chars.
    • The result of (d-2*c) is stored in BX. This is because we need to divide (a+c*b) / (d-2*c), and you were popping (a+c*b) in BX, so, when you do div bx you were doing (d-2*c) / (a+c*b) .
    • Separated the display for quotient and remainder.
    • Added 13,10 line breaks to messages.
    • Fixed shl ax,2 by shl ax,1. One shl is x2, two shl are x2x2.
    • The remainder is obtained from dl because when div uses a word as divisor, the remainder is left in dx.

    Here is your code with the little changes (tested on EMU8086):

    ; --------------------------------------------
    ; Equation=(a+c*b)/d-2*c,
    ; --------------------------------------------.model small
    .stack 100h
    .data
        a   db 0                
        b   db 0
        c   db 0
        d   db 0
        result1 db ?
        result2 db ?
    
    
    
        message1 db 13,10,"Equation: (a+c*b)/d-2*c",13,10,"a=$"
        message2 db 13,10,"b=$"         ;<================= 13,10 IS
        message3 db 13,10,"c=$"         ;<================= LINEBREAK.
        message4 db 13,10,"d=$"         ;<=================
        message5 db 13,10,"Quotient=$"  ;<=================
        message6 db 13,10,"Remainder=$" ;<=================
    .code
    
    start:  mov ax,@data
            mov ds,ax           
    
    
    
            mov ax, seg message1   ;get a and save to a variable
            mov ds,ax   
            mov dx,offset message1
            mov ah, 9h
            int 21h
            mov ah, 1h 
            int 21h
            sub al,30h    ;converting to real number
            mov a,al
    
            mov ax, seg message2 ;get b and save to a variable
            mov ds,ax   
            mov dx,offset message2
            mov ah, 9h
            int 21h
            mov ah, 1h
            int 21h
            sub al,30h    ;converting to real number
            mov b,al
    
    
            mov ax, seg message3    ;get c and save to a variable
            mov ds,ax   
            mov dx,offset message3
            mov ah, 9h
            int 21h
            mov ah, 1h 
            int 21h
            sub al,30h    ;converting to real number
            mov c,al
    
    
            mov ax, seg message4   ;get d and save to a variable
            mov ds,ax   
            mov dx,offset message4
            mov ah, 9h
            int 21h
            mov ah, 1h 
            int 21h
            sub al,30h   ;converting to real number
            mov d,al
    
    
            mov al,b          ; (a+c*b)
            mul c
            mov cl,A    ;<======== MOV A TO CX TO
            mov ch,0    ;<======== ADD IT TO AX.
            add ax,CX   ;<======== C*B + A.
    
           ;push ax     ;<======== NO LONGER NECESSARY BECAUSE
                        ;<======== IN NEXT BLOCK WE USE BX.
    
            mov bl,C    ;<======== MOV C TO BL AND CLEAR
            mov bh,0    ;<======== BH. NOW C IS IN BX.
            shl bx,1    ;<======== 2*c. ONE SHIFT IS x2, TWO SHIFTS ARE x2x2.
            sub d,bl          ;d - 2c
            mov bl,d    ;<======== MOV D TO BL AND CLEAR BH. NOW
            mov bh,0    ;<======== D IS IN BX. BX = (D-2C).
    
           ;pop ax      ;<======== NO LONGER NECESSARY. AX CONTAINS (A+C*B).
    
            mov dx,0    ;<======== CLEAR DX, BECAUSE DIVISOR IS A WORD.
                        ;<======== WHEN DIVISOR IS A WORD, DIV USES DX:AX. 
            div bx      ;<======== dx:ax / bx == DX:(A+C*B) / (D-2C). THIS
                        ;<======== DIVISION IS UNSIGNED, FOR SIGNED USE IDIV.
    
            mov result1,al ;<===== QUOTIENT.
            mov result2,dl ;<===== REMAINDER, BECAUSE DIVISOR IS WORD.
    
            add result1,30h   ;converting to string
            add result2,30h    ;converting to string
    
            mov al,result1
            mov bl,result2
    
          ;DISPLAY QUOTIENT  <=============
            mov ax, seg message5
            mov ds,ax   
            mov dx,offset message5
            mov ah, 9h
            int 21h
            mov al,result1
            mov dl, al
            mov ah , 2h
            int 21h       
          ;DISPLAY REMAINDER  <=============
            mov ax, seg message6
            mov ds,ax   
            mov dx,offset message6
            mov ah, 9h
            int 21h
            mov dl, bl
            mov ah , 2h
            int 21h
    
            mov ax,4C00h        
            int 21h
    
    end     start
    

    Next is your "to do" list:

    • Change the size of operands from DB to DW, to allow your program to handle bigger numbers.
    • Change DIV by IDIV, because DIV is unsigned while IDIV is signed. IDIV will let you handle negative results.
    • Capture numbers with int=21h ah=0Ah as strings (not as single chars). Later, you convert the strings into numbers. Next two links will take you to the procedures to convert from string to number :

    Assembly x86 Date to Number - Breaking a string into smaller sections

    32 bit Calculator in 8086 Assembly

    Finally, the test data :

    (a+c*b) / (d-2*c)
    
    a=1
    b=2
    c=3
    d=8
    
    a+c*b = 1+3*2 = 7
    d-2*c = 8-2*3 = 2
    
    7 / 2 = quotient 3, remainder 1