Reputation: 9
Hello this is assembly language for x86 processors, using visual studio 2019 to compile. I am soley using instructions from the Irvine32 library for the jumps based on flags. I ask one character from user to decide if that one character is a uppercase/lowercase letter, or if user entered a number. If the user entered anything else besides the two, it should fall through the jump commands and just ouput error message and exit out. My problem is that the lower case letters and numbers jump to lower case output. Here is code
.data
digit BYTE "Number",0ah,0dh,0
upper BYTE "Upper case",0ah,0dh,0
lower BYTE "Lower case",0ah,0dh,0
prompt BYTE "Enter input from keyboard",0ah,0dh,0
error BYTE "Error. Neither (0/A)",0ah,0dh,0
.code
main PROC
mov edx, OFFSET prompt
mov eax, 0
call writeString
call readChar
call isLower
cmp eax, 0
jz ISUP
JNZ Lowrr
mov edx, 0
call isDigit
test eax, 0
JZ Number
mov edx, offset error
call writeString
JMP EXITOUT
Lowrr:
mov edx, OFFSET lower
call writeString
jmp EXITOUT
ISUP:
MOV EDX, OFFSET upper
call writeString
JMP EXITOUT
Number:
MOV EDX, OFFSET digit
call writeString
JMP EXITOUT
EXITOUT:
exit
main ENDP
isLower PROC
cmp al, "A"
JnZ LOWERTRUE
jnC LOWERFALSE
cmp al, "Z"
JnZ LOWERTRUE
JC LOWERFALSE
LOWERTRUE:
mov eax, 1
ret
LOWERFALSE:
mov eax, 0
ret
isLower ENDP
isDigit PROC
cmp al, "0"
JZ DigitTRUE
jC DigitFALSE
cmp al, "9"
JZ DigitTRUE
JnC DigitFALSE
DigitTRUE:
mov eax, 1
ret
DigitFALSE:
mov eax, 0
ret
isDigit ENDP
END main
Upvotes: 0
Views: 369
Reputation: 39166
call isLower cmp eax, 0 jz ISUP JNZ Lowrr mov edx, 0 call isDigit test eax, 0 JZ Number
The jz
and jnz
cover every possible outcome from the cmp eax, 0
instruction. Therefore the program will never even reach the call to isDigit. Perhaps that's just as well since the character that was supposed to be in the AL
register isn't there anymore! isLower returns a result in the EAX
register, and thus destroys the character. (AL
is part of EAX
).
When you test a number with zero, the result will always be zero. Thus the code test eax, 0
jz Number
will always jump!
When isLower returns FALSE, then you can't just conclude that the character is uppercase. You can only conclude that the character is not lowercase, nothing else. This code should have been:
call isLower
cmp eax, 1
je Lowrr
cmp al, "0" JZ DigitTRUE jC DigitFALSE cmp al, "9" JZ DigitTRUE JnC DigitFALSE DigitTRUE: mov eax, 1 ret DigitFALSE: mov eax, 0 ret
By itself, the jz DigitTRUE
after comparing to "0" is correct. Same for jz DigitTRUE
after comparing to "9". However these are not productive instructions.
The 10 possible digits form one range that you can easily test in a few instructions that verify the lower bound and the upper bound. Your jc DigitFALSE
after comparing to "0" is fine, but your jnc DigitFALSE
after comparing to "9" sadly will not recognize "9" as a digit (Equality clears the CF)! This is why you wrote that redundant jz DigitTRUE
, isn't it.
cmp al, "A" JnZ LOWERTRUE jnC LOWERFALSE cmp al, "Z" JnZ LOWERTRUE JC LOWERFALSE LOWERTRUE: mov eax, 1 ret LOWERFALSE: mov eax, 0 ret
It's strange to see comparing to uppercase characters in a code that aims to verify for lowercase. And the pair cmp al, "A"
JnZ LOWERTRUE
means that really everything that is not that one character "A" is automatically taken as lowercase. Further analyses then becomes futile.
The 26 possible lowercase characters form one range that you can easily test in a few instructions that verify the lower bound and the upper bound.
And since classifying for lowercase doesn't tell anything useful about uppercase-ness, you will need an isUpper proc too.
Considering where digits, uppercase, and lowercase are in the ASCII table:
48 57 65 90 97 122
0 ... 9 A ... Z a ... z
These are my (shorter) codes for IsDigit, IsUpper, and IsLower. They return CF
clear for TRUE and CF
set for FALSE. That way the character in the AL
register stays intact for subsequent verification:
; IN (al) OUT (CF)
IsDigit PROC
cmp al, "0" ; Lower bound
jb Digit_
cmp al, "9" + 1 ; Upper bound plus 1
cmc
Digit_:
ret
IsDigit ENDP
; IN (al) OUT (CF)
IsUpper PROC
cmp al, "A" ; Lower bound
jb Upper_
cmp al, "Z" + 1 ; Upper bound plus 1
cmc
Upper_:
ret
IsUpper ENDP
; IN (al) OUT (CF)
IsLower PROC
cmp al, "a" ; Lower bound
jb Lower_
cmp al, "z" + 1 ; Upper bound plus 1
cmc
Lower_:
ret
IsLower ENDP
Binding it together becomes extremely simple:
mov edx, OFFSET digit
call IsDigit ; -> CF
jnc WriteIt
mov edx, OFFSET upper
call IsUpper ; -> CF
jnc WriteIt
mov edx, OFFSET lower
call IsLower ; -> CF
jnc WriteIt
mov edx, OFFSET error
WriteIt:
call writeString
Upvotes: 2