如何在年龄计算程序中使用 MASM 汇编语言中的条件语句?

How to use conditional statements in MASM Assembly Language for an age calculating program?

我目前正在上大学汇编语言课程,给我的家庭作业是编写一个程序,其中可以使用出生年月日来 return 年龄. (当前的年月日在程序的早期定义。)

程序的主要部分是条件 if 语句,将输入的年份与当前年份、输入的月份与当前月份以及输入的日期与当前日期进行比较。

还考虑了一些特殊情况,例如输入未来的日期,或输入与当前年份相同的年份,或者即使您输入的日期与当前日期相同将在输出末尾添加“生日快乐”文本的当前日期。

想要的 input/output 将是:

 Enter the year of your birth: **2002**
 Enter the month of your birth: **4**
 You are 19 years old

我得到的input/output是这样的:

 Enter the year of your birth: **2002**
 Enter the month of your birth: **4**
 You are 4294965279 years old

我很确定我搞砸了我对 EAX 和 DWORD 的使用,但我并不肯定。

我在这个问题中包含了整个程序,以便您更好地理解我想要实现的目标。

任何有关我搞砸的地方的提示将不胜感激。

此外,请记住,这只是我在此 class 中的第三次作业,所以不要指望我知道任何高级 MASM 汇编语言术语或技术。

这是代码(为了方便起见,伪代码在右边):

TITLE H03C         (H03C.asm)

; William Sanacore
; 9/23/2021
; H03C
; Description: Write a program that calculates how old you are.

INCLUDE Irvine32.inc

.data
curYear         DWORD   ?
curMonth        DWORD   ?
curDay          DWORD   ?

yearMsg         BYTE    "Enter the year of your birth: ", 0
montMsg         BYTE    "Enter the month of your birth: ", 0
dayMsg          BYTE    "Enter the day of your birth: ", 0
lessyearMsg     BYTE    "You are less than one year old"
youAreMsg       BYTE    "You are ", 0
yearsOldMsg     BYTE    " years old", 0
yearsOldHBMsg   BYTE    " years old, Happy Birthday", 0
notBornMsg      BYTE    "You have not been born yet", 0

year            DWORD   ?
month           DWORD   ?
day             DWORD   ?
age             DWORD   ?

.code
main            PROC                            ; Start
                                
                mov     curYear, 2021           ; curYear = 2021
                                
                mov     curMonth, 9             ; curMonth = 9
        
                mov     curDay, 23              ; curDay = 23
                                
                LEA     EDX, yearMsg            ; Print "Enter the year of your birth: "
                call    WriteString
                                
                call    ReadDec                 ; Input year
                mov     year, DWORD                     
                                
                mov     year, EAX               ; IF year = curYear THEN
                cmp     EAX, curYear                
                jne     ELSE1               
        
        
                LEA     EDX, lessyearMsg        ;    Print "you are less than 1 year old"
                call    WriteString
                jmp     ENDIF1
ELSE1:                                          ; ELSE              
                mov     year, EAX               ;    IF year < curYear THEN
                cmp     EAX, curYear
                jnl     ELSE2

                LEA     EDX, montMsg            ;    Print "Enter the month of your birth: "
                call    WriteString
        
                call    ReadDec                 ;    Input month
                mov     month, DWORD
                                
                mov     year, EAX               ;    age = curYear - year
                sub     EAX, curYear
                mov     age, DWORD
                                
                mov     month, EAX              ;    IF month > curMonth THEN
                cmp     EAX, curMonth
                jng     ELSE3
                                
                mov     age, EAX                ;    age = age - 1
                sub     EAX, '1'
                mov     age, DWORD

                LEA     EDX, youAreMsg          ;    Print "you are "; age; " years old"
                call    WriteString
                mov     age, EAX
                call    WriteDec
                LEA     EDX, yearsOldMsg
                call    WriteString
                jmp     ENDIF2
ELSE3:                                          ;       ELSE                                
                mov     month, EAX              ;      IF month < curMonth THEN
                cmp     EAX, curMonth
                jnl     ELSE4

                LEA     EDX, youAreMsg          ;         Print "you are "; age; " years old"
                call    WriteString
                mov     age, EAX
                call    WriteDec
                LEA     EDX, yearsOldMsg
                call    WriteString
                jmp     ENDIF3
ELSE4:                                          ;      ELSE                         
                LEA     EDX, dayMsg             ;         Print "Enter day of your birth: "
                call    WriteString
        
                call    ReadDec                 ;         Input day
                mov     day, DWORD
        
                mov     day, EAX                ;         IF day > curDay THEN
                cmp     EAX, curDay
                jng     ELSE5

                mov     age, EAX                ;            age = age - 1
                sub     EAX, '1'                        
                mov     age, DWORD                      
                                
                LEA     EDX, youAreMsg          ;            Print "you are "; age; " years old"
                call    WriteString                     
                mov     age, EAX                        
                call    WriteDec                        
                LEA     EDX, yearsOldMsg                        
                call    WriteString                     
                jmp     ENDIF4                                                      
ELSE5:                                          ;         ELSE                              
                mov     day, EAX                ;            IF day < curDay THEN
                cmp     EAX, curDay
                jnl     ELSE6

                LEA     EDX, youAreMsg          ;           Print "you are "; age; " years old"
                call    WriteString                         
                mov     age, EAX                                
                call    WriteDec                            
                LEA     EDX, yearsOldMsg                        
                call    WriteString                         
                jmp     ENDIF5                                                                                              
ELSE6:                                          ;        ELSE                               
                LEA     EDX, youAreMsg          ;           Print "you are "; age; " years old, Happy Birthday"
                call    WriteString                         
                mov     age, EAX                                
                call    WriteDec                            
                LEA     EDX, yearsOldMsg                        
                call    WriteString                         
                jmp     ENDIF6                                                                                  
ENDIF6:                                         ;        ENDIF
                call    CRLF
                exit                        
ENDIF5:                                         ;         ENDIF
                call    CRLF 
                exit                            
ENDIF4:                                         ;      ENDIF
                call    CRLF
                exit                        
ENDIF3:                                         ;   ENDIF
                call    CRLF
                exit                        
ELSE2:                                          ;    ELSE                           
                LEA     EDX, notBornMsg         ;       Print "you haven't been born yet"
                call    WriteString
ENDIF2:                                         ;    ENDIF
                call    CRLF
                exit                        
ENDIF1:                                         ; ENDIF
                call    CRLF                        
                exit                            ; Stop
main            ENDP
                END     main

You are 4294965279 years old

恭喜!请告诉我们您是如何应对的...

开个玩笑,代码有很多问题。下面列出了几个:

call    ReadDec                 ; Input year
mov     year, DWORD                     
mov     year, EAX               ; IF year = curYear THEN
cmp     EAX, curYear                

ReadDec 的结果在 EAX 寄存器中。 mov year, DWORD 指令没有意义!如果您写评论,请将它们放在它们所属的行上。

call    ReadDec                 ; Input year
mov     year, eax
cmp     eax, curYear            ; IF year = curYear THEN
call    ReadDec                 ;    Input month
mov     month, DWORD
mov     year, EAX               ;    age = curYear - year
sub     EAX, curYear
mov     age, DWORD

在您刚刚输入 的这部分代码中,您用这个 [= 破坏了已经建立的 22=] 指令!此代码还执行虚假计算“month - curYear”。

mov     month, EAX              ;    IF month > curMonth THEN
cmp     EAX, curMonth

目标是第一个操作数,源是第二个操作数。从 month 变量加载 EAX 寄存器需要:mov eax, month.

mov     age, EAX                ;    age = age - 1
sub     EAX, '1'
mov     age, DWORD

三行,三个错误。左边是目的地,右边是源头。值“1”是 49,但您只需要 1。'DWORD' 本身没有任何意义。

mov  eax, age   ; Load from memory
sub  eax, 1     ; Decrement
mov  age, eax   ; Store to memory

一个较短的版本是:dec age

LEA     EDX, yearsOldMsg    
call    WriteString
jmp     ENDIF6

最后的“生日快乐”部分忘记实际引用相关消息。

mov  edx, OFFSET yearsOldHBMsg
call WriteString
jmp  ENDIF6

总而言之,代码很难读,你重复了好几遍。也许是不同的方法?


这是 BASIC 中的程序。

Print "Enter the year of your birth: "
Input year
IF year = curYear THEN
  Print "you are less than 1 year old"
ELSE              
  IF year < curYear THEN
    Print "Enter the month of your birth: "
    Input month
    age = curYear - year
    IF month > curMonth THEN
      age = age - 1
      Print "you are "; age; " years old"
    ELSE                                
      IF month < curMonth THEN
        Print "you are "; age; " years old"
      ELSE                         
        Print "Enter day of your birth: "
        Input day
        IF day > curDay THEN
          age = age - 1
          Print "you are "; age; " years old"
        ELSE                              
          IF day < curDay THEN
            Print "you are "; age; " years old"
          ELSE                               
            Print "you are "; age; " years old, Happy Birthday"
          ENDIF
        ENDIF
      ENDIF
    ENDIF
  ELSE                           
    Print "you haven't been born yet"
  ENDIF
ENDIF

您正在尝试非常紧密地遵循 BASIC 代码,可能太紧密了!更好的策略是研究高级示例,找出其意图,然后尽可能高效地用汇编代码编写代码。下面是一个例子 'avoids advanced MASM assembly language terms or techniques':

    mov     curYear, 2021              ; curYear = 2021
    mov     curMonth, 9                ; curMonth = 9
    mov     curDay, 23                 ; curDay = 23
    mov     edx, OFFSET yearMsg        ; Print "Enter the year of your birth: "
    call    WriteString
    call    ReadDec                    ; Input year

    mov     ecx, curYear               ; age = curYear - year
    sub     ecx, eax                   ; (*)
    mov     age, ecx
    mov     edx, OFFSET lessyearMsg    ; "you are less than 1 year old"
    jz      finalMsg
    mov     edx, OFFSET notBornMsg     ; "you haven't been born yet"
    js      finalMsg

    mov     esi, OFFSET yearsOldMsg
    mov     edx, OFFSET montMsg        ; Print "Enter the month of your birth: "
    call    WriteString        
    call    ReadDec                    ; Input month
    mov     month, eax
    cmp     eax, curMonth
    jne     maybeDec

    mov     edx, OFFSET dayMsg         ; Print "Enter day of your birth: "
    call    WriteString
    call    ReadDec                    ; Input day
    mov     day, eax
    cmp     eax, curDay
    jne     maybeDec
    mov     esi, OFFSET yearsOldHBMsg  ; " years old, Happy Birthday"
    jmp     fullMsg

maybeDec:
    jb      fullMsg                    ; (**)
    dec     age                        ; age = age - 1
fullMsg:
    mov     edx, OFFSET youAreMsg      ; " you are"
    call    WriteString                     
    mov     eax, age
    call    WriteDec
    mov     edx, esi                   ; ESI={yearsOldMsg, yearsOldHBMsg}
finalMsg:
    call    WriteString
    call    CRLF                        

() 那些 mov <reg>, OFFSET <label> 指令比 lea <reg>, <label> 指令短一个字节。
(*) 无论如何都需要 age 计算。我们可以使用 SUB 指令的标志结果,而不是执行多个单独的 CMP
(**) 请注意,我确实使用了 unsigned 操作。天和月是无符号数。