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
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.