I am working on a project for class, and it works as required by the rubric, though I am wondering if there is a slightly better way to implement a few things. I was docked a few points for an unnecessary mov
in another project.
Problem 1:
"If—else (34 points): Write a program that asks the user to enter a single digit. If that digit is less 5, you will state so and you will add 5 to it and store it in a variable; if the digit is greater than 5, you will state so and then subtract 5 from it and store it in a variable; if the digit is 5, you will add 3 to it and state so and store it in a variable."
org 100h
mov dx, offset start ;move start of string address 'start' into dx
mov ah, 09h
int 21h ;print the string stored at DS:DX
mov ah, 01h ;function for getting keyboard input
int 21h
sub al, 30h ;subtract 30h to store our number as hexadecimal
mov bl, al ;copying data to BL as the following commands manipulate the data
;at AL.
cmp bl, 5 ;BL = AL
jz ifZero ;jump to ifZero if BL = 5
jl ifLess ;jump to isLess if BL < 5
jg ifGreater ;jump to ifGreater if BL > 5
ifZero: ;direct console output function
mov ah, 06h
mov dl, 0Ah
int 21h
mov dl, 0Dh
int 21h ;print newline and character return
add bl, 03h ;add 3 to BL, BL = 8
mov temp, bl
mov dx, offset eq ;move start of string address 'eq' into dx
mov ah, 09h
int 21h ;print string
jmp exit ;unconditional jump to end program
ifLess: ;direct console output function
mov ah, 06h
mov dl, 0aH
int 21h
mov dl, 0Dh
int 21h ;print newline and character return
add bl, 05h ;add 5 to BL
mov temp, bl
mov dx, offset less ;move start of string address 'less' into dx
mov ah, 09h
int 21h ;print string
jmp exit ;unconditional jump to end program
ifGreater:
mov ah, 06h
mov dl, 0ah
int 21h
mov dl, 0dh
int 21h ;print newline and character return
sub bl, 05h ;subtract 5 from BL
mov temp, bl
mov dx, offset great ;move starting address of string 'great' into dx
mov ah, 09h
int 21h ;print string
jmp exit ;unconditional jump to end program
exit:
ret
temp db ?
start db "Please enter a number: $"
less db "Less than 5... adding 5 $"
great db "Greater than 5... subtracting 5 $"
eq db "Equal to 5... adding 3 $"
Problem 3:
Counter-controlled loop. The program will ask the user to enter a character and then it will display that character with a label five times
For example:
Enter a character: A
You entered: A
org 100h
mov cx, 05h ;counter controlled loop, start as 5
LabelLoop:
mov dx, offset prompt ;move string offset to dx
mov ah, 09h ;function for printing string from dx
int 21h
mov ah, 01h ;function to read character from keyboard
int 21h
mov bl, al ;preserving character read by copying to BL
;as register data for AL will be changing
;due to various functions
mov ah, 06h ;function for direct console output
mov dl, 0ah
int 21h
mov dl, 0dh ;these just make the text appear on a new
;line
int 21h
mov dx, offset output ;move the memory offset of output to dx
mov ah, 09h ;printing another string
int 21h
mov ah, 02h ;function to write a character to console
;gets the value from DL
mov dl, bl ;so we copy BL to DL and print it
int 21h
jmp newLine ;we unconditionally jump to the newLine
;label and print a new line for the program
;to run again
newLine:
mov ah, 06h
mov dl, 0ah
int 21h
mov dl, 0dh
int 21h
loop LabelLoop ;we jump to LabelLoop and CX = CX - 1
mov dx, offset goodbye
mov ah, 09h
int 21h
ret
prompt db 'Enter a character: $'
output db 'You entered: $'
goodbye db 'Good bye!$'
I realize that AL = DL
after:
mov ah, 06h
mov dl, 0ah
int 21h ;AL = DL after execution
The version of the program that prints everything on its own line is worth extra points, so I opted to do that. When printing a character to console it gets its data from DL, but if I have to print a newline before that character, that data in AL
is gone. Is sending that data to BL necessary? Is there a better option?
1 Answer 1
Write a program that asks the user to enter a single digit
This is where your program has its first error. You trust the user at the keyboard to actually input a digit, but your program should make sure it indeed got a digit!
InputAgain:
mov dx, offset start ;move start of string address 'start' into dx
mov ah, 09h
int 21h ;print the string stored at DS:DX
mov ah, 01h ;function for getting keyboard input
int 21h
cmp al, '0'
jb InputAgain
cmp al, '9'
ja InputAgain
sub al, 30h ;subtract 30h to store our number as hexadecimal
The solution I've presented above will work out nicer if you add a single CR code to the message at start.
start db 13,"Please enter a number: $"
cmp bl, 5 ;BL = AL jz ifZero ;jump to ifZero if BL = 5 jl ifLess ;jump to isLess if BL < 5 jg ifGreater ;jump to ifGreater if BL > 5 ifZero:
The first improvement you should do is making use of the possibility to fall-through in the code. Don't use jz ifZero
but rather fall through as equality is the only state that remains after jl
and jg
. Also ifEqual would be a more correct name for this state.
cmp bl, 5 ;BL = AL
jl ifLess ;jump to isLess if BL < 5
jg ifGreater ;jump to ifGreater if BL > 5
ifEqual:
A second optimization will be to get rid of all of those direct console outputs for CR and LF. You should incorporate these in the messages that you will print. Doing so will also remove the need to copy AL to BL using mov bl, al
(you specifically asked this):
less db 13,10,"Less than 5... adding 5 $"
great db 13,10,"Greater than 5... subtracting 5 $"
eq db 13,10,"Equal to 5... adding 3 $"
Do observe that I wrote 13,10 and not 10,13. On the DOS platform convention dictates the use of CRLF=13,10. This might not seem too important to you but recently I came across a question on Stack Overflow where someone suffered a malfunctioning emulator precisely because of this!
Here's another opportunity to fall through:
jmp exit ;unconditional jump to end program exit:
Yet another such opportunity:
jmp newLine ;we unconditionally jump to the newLine newLine: