简体   繁体   中英

Identifying numbers and letters using Irvine library

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

The logic in the main part

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 aswell 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 destroyes the character. ( AL is part of EAX ).

  • When you test a number with zero, the result will always be zero. 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 and nothing else. This code should have been:

     call isLower cmp eax, 1 je Lowrr

The logic in isDigit

 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.

The logic in isLower

 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 too 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 verifications:

; 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM