使用 Irvine 库识别数字和字母

问题描述 投票:0回答:1

您好,这是 x86 处理器的汇编语言,使用 Visual Studio 2019 进行编译。 我仅使用 Irvine32 库中的指令进行基于标志的跳转。 我要求用户输入一个字符来决定该字符是否是大写/小写字母,或者用户是否输入了数字。如果用户输入了除这两个命令之外的任何其他内容,则它应该通过跳转命令并仅输出错误消息并退出。我的问题是小写字母和数字跳转到小写输出。这是代码

.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
assembly x86 masm irvine32
1个回答
0
投票

主体部分的逻辑

call isLower
cmp eax, 0
jz ISUP
JNZ Lowrr

mov edx, 0
call isDigit
test eax, 0
JZ Number
  • jz
    jnz
    涵盖了
    cmp eax, 0
    指令的所有可能结果。因此,程序甚至永远不会调用 isDigit。也许这样也好,因为原本应该出现在
    AL
    寄存器中的字符已经不存在了! isLower
    EAX
    寄存器中返回结果,从而销毁该字符。 (
    AL
    EAX
    的一部分)。

  • 当你用零测试一个数字时,结果将始终为零。因此代码

    test eax, 0
    jz Number
    总是会跳转!

  • isLower返回FALSE时,那么你不能仅仅断定该字符是大写的。你只能断定该字符不是小写,除此之外别无其他。这段代码应该是:

      call isLower
      cmp  eax, 1
      je   Lowrr
    

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

就其本身而言,与“0”比较后的

jz DigitTRUE
是正确的。与“9”比较后,
jz DigitTRUE
也一样。然而,这些都不是富有成效的指示。
10 个可能的数字构成一个范围,您可以通过几条指令轻松测试该范围,以验证下限和上限。与“0”比较后的
jc DigitFALSE
没问题,但与“9”比较后的
jnc DigitFALSE
遗憾的是不会将“9”识别为数字(相等清除 CF)!这就是为什么你写了那些多余的
jz DigitTRUE
,不是吗。

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

在旨在验证小写的代码中与大写字符进行比较很奇怪。而

cmp al, "A"
JnZ LOWERTRUE
这对意味着实际上除了一个字符“A”之外的所有内容都会自动视为小写。进一步的分析就变得毫无意义。
26 个可能的小写字符形成一个范围,您可以通过几条指令轻松测试该范围,以验证下限和上限。
由于对小写字母进行分类并不能告诉你任何有关大写字母的有用信息,因此您还需要一个 isUpper 过程。


考虑数字、大写字母和小写字母在 ASCII 表中的位置:

      48   57       65   90       97   122
      0 ... 9       A ... Z       a ... z

这些是我的 IsDigitIsUpperIsLower 的(较短)代码。它们返回

CF
清除为 TRUE 和
CF
设置为 FALSE。这样,
AL
寄存器中的字符就可以保持完整以供后续验证:

; 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

将其绑定在一起变得极其简单:

  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
© www.soinside.com 2019 - 2024. All rights reserved.