【问题标题】:Created a program using emu8086 that ask a user for a response from 1-4, but only response 1 and 2 work.使用 emu8086 创建了一个程序,要求用户从 1-4 做出响应,但只有响应 1 和 2 有效。
【发布时间】:2017-11-26 03:15:06
【问题描述】:

对于一个学校项目,我被告知要创建一个程序,向用户提出两个问题,每个问题都有多个选择。对于第一个问题,我要求用户从 1 到 4 中选择一个选项,但第三个和第四个选项不起作用。如果有人知道如何解决此问题,我将非常感激知道为什么会发生这种情况。

    BeerSelection db 'Please choose a style of beer?',0Dh,0Ah,0Ah,'Press 1 for IPA, 2 for Wheat Beer, 3 for Dark Lager, or 4 for Brown Ale.',0Dh,0Ah,0Ah,'$'
    BeerChoice db 'Which beer would you like?',0Dh,0Ah,0Ah,'Press 1 for the first beer and 2 for the second beer',0Dh,0Ah,0Ah,'$'
    Inputs db 00h,00h,
    Searching db 'Pouring Your Beer Selection...',0Ah,0Ah,0Dh,'$'
    DogfishHead db 'Pouring 60 Minute from Dogfish Head.','$'
    TreeHouse db 'Pouring Julius from Tree House Brewing Company.','$'
    BlueMoon db 'Pouring Belgiun Wheat from Blue Moon.','$'
    FunkyBuddha db 'Pouring Floridian Hefeweizen from Funky Buddha.','$'
    Metropolitan db 'Pouring Magnetron Black Lager from Metropolitan Brewing.','$'
    Yuengling db 'Pouring Traditional Lager from Yuengling.','$'
    CigarCity db 'Pouring Maduro from Cigar City.','$'
    LostCoast db 'Pouring Raspberry Brown Ale from Lost Coast Brewery.','$'
    Dispensing db 0Ah,0Ah,0Dh,'Prost!','$'

    .code

    ;start of main program

    CALL MYTITLEPAGE

    Call GETINPUTS

    MOV AH,09h; Prompt pouring beer
    MOV DX,offset Searching
    INT 21h

    ;Decision Tree 
    BeerTypes: MOV AL,Inputs[0] 
        CMP AL,01h
        JE IPA
        JMP Wheat
        JMP Lager
        JMP Ale
IPA:   MOV AL,Inputs[1]
        CMP AL,01h
        JE IPABeer1
        CMP AL,02h
        JE IPABeer2
Wheat:   MOV AL,Inputs[1]
        CMP AL,01h
        JE WheatBeer1
        CMP AL,02h
        JE WheatBeer2
Lager:   MOV AL,Inputs[1]
        CMP AL,01h
        JE LagerBeer1
        CMP AL,02h
        JE LagerBeer2
Ale:   MOV AL,Inputs[1]
        CMP AL,01h
        JE AleBeer1
        CMP AL,02h
        JE AleBeer2 

【问题讨论】:

  • JMP Wheat JMP Lager JMP Ale 不起作用。它只会到达第一个。您应该逐步使用调试器并观察事物分支的位置。这应该很容易为您调试。

标签: assembly dos x86-16 emu8086


【解决方案1】:

假设Call GETINPUTSInputs[0](1、2、3 或 4)和Inputs[1](1 或 2)中都给出了有效的选择。

天真的方法是像在下一个 sn-p 中那样测试每个案例:

BeerTypes:
    mov     al, Inputs[0]  ;Values are in [1,4]
    cmp     al, 1
    je      IPA
    cmp     al, 2
    je      Wheat
    cmp     al, 3
    je      Lager
    cmp     al, 4
    je      Ale

鉴于已知值在 [1,4] 范围内,因此不需要第 4 次比较,因为它总是会跳转。您可以将 cmp al, 4 je Ale 替换为简单的 jmp Ale

现在,我们可以通过调查更多的零标志(测试是否相等)来进一步减少比较次数。如果与值2比较,发现置位了Carry Flag,那么就知道AL中的值小于2,这样就可以省略cmp al, 1指令了。

BeerTypes:
    mov     al, Inputs[0]  ;Values are in [1,4]
    cmp     al, 2
    jb      IPA            ;AL=1
    je      Wheat          ;AL=2
    cmp     al, 3
    je      Lager          ;AL=3
    jmp     Ale            ;AL=4

IPA:
    MOV AL,Inputs[1]
    CMP AL,01h
    JE IPABeer1
    CMP AL,02h
    JE IPABeer2
Wheat:
    MOV AL,Inputs[1]
    CMP AL,01h

鉴于已知值在 [1,2] 范围内,您可以将 cmp al, 2 je IPABeer2 替换为简单的 jmp IPABeer2WheatLagerAle 也是如此。

IPA:
    mov     al, Inputs[1]
    cmp     al, 1
    je      IPABeer1
    jmp     IPABeer2
Wheat:

----------------------------------------------- -------------

如果Call GETINPUTS 有可能返回比有效选择更多的信息,那么您需要通过编写防御性代码来防范这种情况,尤其是避免在下面的代码中失败。

BeerTypes:
    mov     al, Inputs[0]  ;Values could be anything
    dec     al             ;[1,4] -> [0,3]
    cmp     al, 1
    jb      IPA            ;Inputs[0]=1
    je      Wheat          ;Inputs[0]=2
    cmp     al, 3
    jb      Lager          ;Inputs[0]=3
    je      Ale            ;Inputs[0]=4
    jmp     InputError
IPA:
    mov     al, Inputs[1]  ;Values could be anything
    dec     al             ;[1,2] -> [0,1]
    cmp     al, 1
    jb      IPABeer1       ;Inputs[1]=1
    je      IPABeer2       ;Inputs[1]=2
    jmp     InputError
Wheat:
    ...

【讨论】:

    【解决方案2】:
        CMP AL,01h
    

    CMP instruction 将计算减法 (temp = AL - 1),与 SUB instruction 完全相同,但结果值被丢弃(不存储在任何地方,在这种情况下 AL 保持不变),并且只有标志已更新。

        JE IPA
    

    JE is acronym of "jump equal",在内部作为“设置 ZeroFlag 时跳转”。和JZ指令是一样的,JE只是它的别名,用于更好地语义阅读源代码,更准确地显示程序员的意图,就像在这种情况下你想跳转,因为AL等于1 ,不是因为涉及到一些零(虽然有,因为1 - 1 = 0)。如果这将是一些倒计时循环,在计数器达到零后提前退出,那么jz 别名对于源阅读器来说更准确。

        JMP Wheat
    

    JMP 无论如何都会跳。即使AL 包含 2、3 或 4。

        JMP Lager
        JMP Ale
    

    这两个是无法访问的代码。

    因此,如果您想跳转到 Ale 以获取包含值 4 的 AL,您可以像第一个一样进行类似的测试:

        CMP AL,4
        JE Ale
    

    您可以将所有jmp 修复为cmp+je,并在最后一个JE Ale 之后添加另一个报告无效输入值的代码(超出1..4 范围)。或者只使用jmp Ale 作为没有cmp 的最后一个,所以它会为任何其他输入做到这一点。

    【讨论】:

      猜你喜欢
      • 2012-12-28
      • 1970-01-01
      • 2016-10-28
      • 1970-01-01
      • 1970-01-01
      • 2019-06-05
      • 2018-04-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多