if-statementassemblyconditional-statementsmasmmasm32

How to use conditional statements in MASM Assembly Language for an age calculating program?


I am currently taking an Assembly Language college course and the homework assignment that I was given was to code a program in which a birth year, month, and day can be used in order to return an age. (The current year, month, and day are defined early on in the program.)

The main bulk of the program is conditional if-statements that compare the year input to the current year, month input to the current month, and day input to the current day.

There are also special scenarios that are taken into account such as inputting a date that is in the future, or inputting a year that is equal to the current year, or even if the date that you entered is the same as the current date which would add text that says "Happy Birthday" to the end of the output.

A desired input/output would be:

 Enter the year of your birth: **2002**
 Enter the month of your birth: **4**
 You are 19 years old

The input/output that I am getting is this:

 Enter the year of your birth: **2002**
 Enter the month of your birth: **4**
 You are 4294965279 years old

I am pretty sure that I am screwing up my uses of EAX, and DWORD but I'm not positive.

I am including the entire program in this question so that you have a better understanding of what I am trying to achieve.

Any tips on where I have messed up would be greatly appreciated.

Also, remember that this is only my third assignment in this class so don't expect me to know any advanced MASM assembly language terms or techniques.

Here is the code (Pseudo-code is on the right for your convienience):

TITLE H03C         (H03C.asm)

; William Sanacore
; 9/23/2021
; H03C
; Description: Write a program that calculates how old you are.

INCLUDE Irvine32.inc

.data
curYear         DWORD   ?
curMonth        DWORD   ?
curDay          DWORD   ?

yearMsg         BYTE    "Enter the year of your birth: ", 0
montMsg         BYTE    "Enter the month of your birth: ", 0
dayMsg          BYTE    "Enter the day of your birth: ", 0
lessyearMsg     BYTE    "You are less than one year old"
youAreMsg       BYTE    "You are ", 0
yearsOldMsg     BYTE    " years old", 0
yearsOldHBMsg   BYTE    " years old, Happy Birthday", 0
notBornMsg      BYTE    "You have not been born yet", 0

year            DWORD   ?
month           DWORD   ?
day             DWORD   ?
age             DWORD   ?

.code
main            PROC                            ; Start
                                
                mov     curYear, 2021           ; curYear = 2021
                                
                mov     curMonth, 9             ; curMonth = 9
        
                mov     curDay, 23              ; curDay = 23
                                
                LEA     EDX, yearMsg            ; Print "Enter the year of your birth: "
                call    WriteString
                                
                call    ReadDec                 ; Input year
                mov     year, DWORD                     
                                
                mov     year, EAX               ; IF year = curYear THEN
                cmp     EAX, curYear                
                jne     ELSE1               
        
        
                LEA     EDX, lessyearMsg        ;    Print "you are less than 1 year old"
                call    WriteString
                jmp     ENDIF1
ELSE1:                                          ; ELSE              
                mov     year, EAX               ;    IF year < curYear THEN
                cmp     EAX, curYear
                jnl     ELSE2

                LEA     EDX, montMsg            ;    Print "Enter the month of your birth: "
                call    WriteString
        
                call    ReadDec                 ;    Input month
                mov     month, DWORD
                                
                mov     year, EAX               ;    age = curYear - year
                sub     EAX, curYear
                mov     age, DWORD
                                
                mov     month, EAX              ;    IF month > curMonth THEN
                cmp     EAX, curMonth
                jng     ELSE3
                                
                mov     age, EAX                ;    age = age - 1
                sub     EAX, '1'
                mov     age, DWORD

                LEA     EDX, youAreMsg          ;    Print "you are "; age; " years old"
                call    WriteString
                mov     age, EAX
                call    WriteDec
                LEA     EDX, yearsOldMsg
                call    WriteString
                jmp     ENDIF2
ELSE3:                                          ;       ELSE                                
                mov     month, EAX              ;      IF month < curMonth THEN
                cmp     EAX, curMonth
                jnl     ELSE4

                LEA     EDX, youAreMsg          ;         Print "you are "; age; " years old"
                call    WriteString
                mov     age, EAX
                call    WriteDec
                LEA     EDX, yearsOldMsg
                call    WriteString
                jmp     ENDIF3
ELSE4:                                          ;      ELSE                         
                LEA     EDX, dayMsg             ;         Print "Enter day of your birth: "
                call    WriteString
        
                call    ReadDec                 ;         Input day
                mov     day, DWORD
        
                mov     day, EAX                ;         IF day > curDay THEN
                cmp     EAX, curDay
                jng     ELSE5

                mov     age, EAX                ;            age = age - 1
                sub     EAX, '1'                        
                mov     age, DWORD                      
                                
                LEA     EDX, youAreMsg          ;            Print "you are "; age; " years old"
                call    WriteString                     
                mov     age, EAX                        
                call    WriteDec                        
                LEA     EDX, yearsOldMsg                        
                call    WriteString                     
                jmp     ENDIF4                                                      
ELSE5:                                          ;         ELSE                              
                mov     day, EAX                ;            IF day < curDay THEN
                cmp     EAX, curDay
                jnl     ELSE6

                LEA     EDX, youAreMsg          ;           Print "you are "; age; " years old"
                call    WriteString                         
                mov     age, EAX                                
                call    WriteDec                            
                LEA     EDX, yearsOldMsg                        
                call    WriteString                         
                jmp     ENDIF5                                                                                              
ELSE6:                                          ;        ELSE                               
                LEA     EDX, youAreMsg          ;           Print "you are "; age; " years old, Happy Birthday"
                call    WriteString                         
                mov     age, EAX                                
                call    WriteDec                            
                LEA     EDX, yearsOldMsg                        
                call    WriteString                         
                jmp     ENDIF6                                                                                  
ENDIF6:                                         ;        ENDIF
                call    CRLF
                exit                        
ENDIF5:                                         ;         ENDIF
                call    CRLF 
                exit                            
ENDIF4:                                         ;      ENDIF
                call    CRLF
                exit                        
ENDIF3:                                         ;   ENDIF
                call    CRLF
                exit                        
ELSE2:                                          ;    ELSE                           
                LEA     EDX, notBornMsg         ;       Print "you haven't been born yet"
                call    WriteString
ENDIF2:                                         ;    ENDIF
                call    CRLF
                exit                        
ENDIF1:                                         ; ENDIF
                call    CRLF                        
                exit                            ; Stop
main            ENDP
                END     main

Solution

  • You are 4294965279 years old

    Congratulations! Please tell us how you're coping...

    All joking aside, the code has a lot of problems. Several are listed below:

    call    ReadDec                 ; Input year
    mov     year, DWORD                     
    mov     year, EAX               ; IF year = curYear THEN
    cmp     EAX, curYear                
    

    The result of ReadDec is in the EAX register. The mov year, DWORD instruction makes no sense! If you write comments, place them on the line they belong to.

    call    ReadDec                 ; Input year
    mov     year, eax
    cmp     eax, curYear            ; IF year = curYear THEN
    
    call    ReadDec                 ;    Input month
    mov     month, DWORD
    mov     year, EAX               ;    age = curYear - year
    sub     EAX, curYear
    mov     age, DWORD
    

    In this part of your code where you've just inputted the month, you destroy the already established year with this mov year, EAX instruction! Also this code performs the bogus calculation "month - curYear".

    mov     month, EAX              ;    IF month > curMonth THEN
    cmp     EAX, curMonth
    

    The destionation is the first operand and the source is the second operand. Loading the EAX register from the month variable requires: mov eax, month.

    mov     age, EAX                ;    age = age - 1
    sub     EAX, '1'
    mov     age, DWORD
    

    Three lines, three errors. Destination on the left, source on the right. The value '1' is 49, but you need just the 1. 'DWORD' has no meaning by itself.

    mov  eax, age   ; Load from memory
    sub  eax, 1     ; Decrement
    mov  age, eax   ; Store to memory
    

    A shorter version is: dec age

    LEA     EDX, yearsOldMsg    
    call    WriteString
    jmp     ENDIF6
    

    This final "Happy Birthday" part forgets to actually refer to the relevant message.

    mov  edx, OFFSET yearsOldHBMsg
    call WriteString
    jmp  ENDIF6
    

    All in all, the code is hard to read and you repeat yourself several times. Perhaps a different approach?


    This is the program in BASIC.

    Print "Enter the year of your birth: "
    Input year
    IF year = curYear THEN
      Print "you are less than 1 year old"
    ELSE              
      IF year < curYear THEN
        Print "Enter the month of your birth: "
        Input month
        age = curYear - year
        IF month > curMonth THEN
          age = age - 1
          Print "you are "; age; " years old"
        ELSE                                
          IF month < curMonth THEN
            Print "you are "; age; " years old"
          ELSE                         
            Print "Enter day of your birth: "
            Input day
            IF day > curDay THEN
              age = age - 1
              Print "you are "; age; " years old"
            ELSE                              
              IF day < curDay THEN
                Print "you are "; age; " years old"
              ELSE                               
                Print "you are "; age; " years old, Happy Birthday"
              ENDIF
            ENDIF
          ENDIF
        ENDIF
      ELSE                           
        Print "you haven't been born yet"
      ENDIF
    ENDIF
    

    You are trying to follow the BASIC code very closely, too closely probably! A better strategy is to study the high level example, find out what is intended, and then code it in assembly as efficient as possible. Below is an example that also 'avoids advanced MASM assembly language terms or techniques':

        mov     curYear, 2021              ; curYear = 2021
        mov     curMonth, 9                ; curMonth = 9
        mov     curDay, 23                 ; curDay = 23
        mov     edx, OFFSET yearMsg        ; Print "Enter the year of your birth: "
        call    WriteString
        call    ReadDec                    ; Input year
    
        mov     ecx, curYear               ; age = curYear - year
        sub     ecx, eax                   ; (*)
        mov     age, ecx
        mov     edx, OFFSET lessyearMsg    ; "you are less than 1 year old"
        jz      finalMsg
        mov     edx, OFFSET notBornMsg     ; "you haven't been born yet"
        js      finalMsg
    
        mov     esi, OFFSET yearsOldMsg
        mov     edx, OFFSET montMsg        ; Print "Enter the month of your birth: "
        call    WriteString        
        call    ReadDec                    ; Input month
        mov     month, eax
        cmp     eax, curMonth
        jne     maybeDec
    
        mov     edx, OFFSET dayMsg         ; Print "Enter day of your birth: "
        call    WriteString
        call    ReadDec                    ; Input day
        mov     day, eax
        cmp     eax, curDay
        jne     maybeDec
        mov     esi, OFFSET yearsOldHBMsg  ; " years old, Happy Birthday"
        jmp     fullMsg
    
    maybeDec:
        jb      fullMsg                    ; (**)
        dec     age                        ; age = age - 1
    fullMsg:
        mov     edx, OFFSET youAreMsg      ; " you are"
        call    WriteString                     
        mov     eax, age
        call    WriteDec
        mov     edx, esi                   ; ESI={yearsOldMsg, yearsOldHBMsg}
    finalMsg:
        call    WriteString
        call    CRLF                        
    

    () Those mov <reg>, OFFSET <label> instructions are one byte shorter than the lea <reg>, <label> instructions.
    (*) The age calculation is needed anyway. We can use the flag results from the SUB instruction instead of doing multiple separate CMP's.
    (**) Please note that I did use an unsigned operation. Days and month are unsigned quantities.