(汇编 8086) 如何显示堆栈中的一个字母?

(Assembly 8086) How to display a letters from the stack?

我需要编写一个程序,从用户(控制台)获取字母,直到输入字母 'Z'(例如:ABCZ)。字母必须放在堆栈上。完成输入后,程序应按相反顺序从堆栈中打印字母(例如:CBA),然后再次按字母顺序从堆栈中打印字母(例如:ABC)。我写了程序,但最后一部分不正确。该程序不按字母顺序显示堆栈中的字母,第一个字母除外。倒序显示后想继续用SP

    DATA SEGMENT
        MESSAGE DB "ENTER CHARACTER :$"
    DATA ENDS 

    SSEG SEGMENT STACK    
        DB 100H DUP (?)
    SSEG ENDS  

    CODE SEGMENT
        ASSUME CS:CODE, DS:DATA, SS:SSEG
    START:
        MOV AX,DATA
        MOV DS,AX 

        LEA DX,MESSAGE   ;print String or Message present in the
        MOV AH,9         ;character Array till $  symbol which 
        INT 21H          ;tells the compiler to stop.

        MOV CL,0         ;COUNTER 1
        MOV SI,0         ;COUNTER 2


    GET_CHAR: 
        MOV AH,1         ;read a character from console and save                          
        INT 21H          ;the value entered in variable CHAR in its ASCII form.
        MOV AH,0
        MOV BL,'Z'     
        CMP AL,BL
        JE  REV_PRINT
        PUSH AX
        INC CL
        INC SI
        JMP GET_CHAR

        PUSH BP           ;base pointer:  Offset address relative to SS

    REV_PRINT:    
        MOV BP,SP    
        CMP CL,0
        JE ABC_PRINT     
        MOV DX,[BP]
        MOV AH,02h        ;display the character that stored in DX.
        INT 21H
        ADD SP,2      
        DEC CL
        JMP REV_PRINT

    ABC_PRINT: 
        CMP SI,0
        JE EXIT 

        MOV AH,02h        ;display the character that stored in DX.
        INT 21H

        SUB SP,2
        MOV BP,SP         
        MOV DX,[BP]         
        DEC SI    
        JMP ABC_PRINT

    EXIT: 
        MOV AH,4CH       ;exit to dos or exit to operating system.
        INT 21H 

    CODE ENDS
        END START

Ped7g 帮助我后的最终代码:

    DATA SEGMENT
        MESSAGE DB "ENTER CHARACTER :$"
    DATA ENDS 

    SSEG SEGMENT STACK    
        DB 100H DUP (?)
    SSEG ENDS  

    CODE SEGMENT
        ASSUME CS:CODE, DS:DATA, SS:SSEG
    START:
        MOV AX,DATA
        MOV DS,AX 

        LEA DX,MESSAGE   ;print String or Message present in the
        MOV AH,9         ;character Array till $  symbol which 
        INT 21H          ;tells the compiler to stop.

        MOV CL,0         ;COUNTER 1
        MOV SI,0         ;COUNTER 2


    GET_CHAR: 
        MOV AH,1         ;read a character from console and save                          
        INT 21H          ;the value entered in AX in its ASCII form.
        MOV AH,0
        MOV BL,'Z'     
        CMP AL,BL
        JE  PREP_TO_PRINT
        PUSH AX
        INC CL
        INC SI
        JMP GET_CHAR

    PREP_TO_PRINT:
        PUSH SI           ; store counter
        PUSH BP           ; base pointer:  Offset address relative to SS
        MOV  BP,SP
        ADD  BP,4         ; make it point to the last letter (BP+SI stored = 4B)
    REV_PRINT:
        TEST  CL,CL       ;until CL is not zero
        JE    ABC_PRINT
        MOV   DL,[BP]
        MOV   AH,02h      ;display the character that stored in DL.
        INT   21h
        ADD   BP,2
        DEC   CL
        JMP   REV_PRINT
    ABC_PRINT:
        TEST  SI,SI
        JE    EXIT
        SUB   BP,2        ; BP was +2 after first character
        MOV   DL,[BP]
        MOV   AH,02h      ;display the character that stored in DL.
        INT   21h
        DEC   SI
        JMP   ABC_PRINT
    EXIT:
        POP   BP          ; restore BP to original value (just for exercise)
    ; release all characters from stack (SP += 2*char_counter)
        POP   SI
        SHL   SI,1
        ADD   SP,SI
    ; here the SP should point to original value from before char input
    ; you may want to verify these assumptions in debugger,
    ; to see yourself how the stack works (also open memory view on ss:sp area)

        MOV AH,4CH       ;exit to dos or exit to operating system.
        INT 21H 

    CODE ENDS
        END START

在反向打印中,您执行 add sp,2,从堆栈中释放存储的字母。

虽然技术上它会保留在内存中,但下一个 int 21h(或同时发生的任何中断)将使用该堆栈内存来存储 return 地址和其他内部信息,覆盖旧字母。

你可以做的是继续使用 bp 来寻址堆栈(在打印循环中更改 bp),但通过在两种方式都打印它们之前不释放字母来保持它的分配(同时不更改 sp,仅在打印所有内容之后)。

喜欢:

        ...
        JE  REV_PRINT
        PUSH AX
        INC CL
        INC SI
        JMP GET_CHAR

    REV_PRINT:
        PUSH SI           ; store counter
        PUSH BP           ; base pointer:  Offset address relative to SS
        MOV  BP,SP
        ADD  BP,4         ; make it point to the last letter (BP+SI stored = 4B)

    REV_LOOP:
        TEST  CL,CL
        JE    ABC_PRINT
        MOV   DL,[BP]
        MOV   AH,02h      ;display the character that stored in DL.
        INT   21h
        ADD   BP,2
        DEC   CL
        JMP   REV_LOOP

    ABC_PRINT:
        TEST  SI,SI
        JE    EXIT
        SUB   BP,2        ; BP was +2 after first character
        MOV   DL,[BP]
        MOV   AH,02h      ;display the character that stored in DL.
        INT   21h
        DEC   SI
        JMP   ABC_PRINT

    EXIT:
        POP   BP          ; restore BP to original value (just for exercise)
        ; release all characters from stack (SP += 2*char_counter)
        POP   SI
        SHL   SI,1
        ADD   SP,SI
        ; here the SP should point to original value from before char input
        ; you may want to verify these assumptions in debugger,
        ; to see yourself how the stack works (also open memory view on ss:sp area)
        ...