(Assembly 8086)如何显示堆栈中的字母?

时间:2018-01-24 06:57:25

标签: assembly stack x86-16

我需要编写一个程序来获取用户(控制台)的信件,直到输入字母'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

enter image description here

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

1 个答案:

答案 0 :(得分:1)

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

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

你可以做的是继续使用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)
        ...