Search code examples
assemblyasciidosx86-16

Interchange Letters From String in Assembly Language 8086


I have a very simple problem that i need to achieve. First you enter a string, the first output should copy the last letter of the string and replace the first letter of the string and then the last letter should be replace with the first letter. The second output should capitalize the first letter of the string. I've already did the second output, my problem now is the first output. Please see the expected result below.

Expected Result

Enter string: jon jones
son jonej
Jon jones

Current Code

.MODEL SMALL
.STACK 100H
.DATA        
    INPUT_STRING          DB 10,13,"Enter string: $"    
    USER_INPUT_STRING     DB 80 DUP('$') 
    BREAKLINE             DB 10, 13, "$" 
.CODE
    MOV AX, @DATA
    MOV DS, AX  

    LEA DX,INPUT_STRING
    MOV AH,09H
    INT 21H

    LEA DX, USER_INPUT_STRING
    MOV AH, 0AH
    INT 21H  

    LEA DX, BREAKLINE
    MOV AH, 09H
    INT 21H  

    SUB USER_INPUT_STRING + 2, 32       ;Capitalize
    MOV AH, 02H
    INT 21H 

    LEA DX, BREAKLINE
    MOV AH, 09H
    INT 21H  

    LEA DX, USER_INPUT_STRING + 2       ;Output of capitalize
    MOV AH, 09H
    INT 21H

    LEA DX, BREAKLINE
    MOV AH, 09H
    INT 21H       

    MOV AH, 4CH
    INT 21H
END

allowed commands

mov, lea, int, inc, dec, add, sub, proc, re, db

Solution

  • The buffer of Int 21/AH=0Ah has three parts: size, length, string. The size is the maximal size of the string and must be initialized.

    Change

    USER_INPUT_STRING     DB 80 DUP('$')
    

    to

    USER_INPUT_STRING     DB 80, 0, 80 DUP('$')
    

    Consider, that the string starts at USER_INPUT_STRING + 2. There is its first character. After you have entered the string, you will find the length of the string you have entered at USER_INPUT_STRING + 1, in this case 09h. So, you'll find the last character of the entered string at USER_INPUT_STRING + 2 + (9 - 1). Use registers to swap the values at those memory addresses:

    .MODEL SMALL
    .STACK 100H
    .DATA
        INPUT_STRING          DB 13,10,"Enter string: $"
        USER_INPUT_STRING     DB 80, 0, 80 DUP('$')
        BREAKLINE             DB 13, 10, "$"
    .CODE
        MOV AX, @DATA
        MOV DS, AX
    
        LEA DX,INPUT_STRING
        MOV AH,09H
        INT 21H
    
        LEA DX, USER_INPUT_STRING
        MOV AH, 0AH
        INT 21H
    
        LEA DX, BREAKLINE
        MOV AH, 09H
        INT 21H
    
        MOV AL, USER_INPUT_STRING + 2
        XOR CX, CX
        MOV CL, USER_INPUT_STRING + 1
        MOV BX, OFFSET USER_INPUT_STRING + 2
        ADD BX, CX
        DEC BX
        MOV AH, [BX]
        MOV [BX], AL
        MOV USER_INPUT_STRING + 2, AH
    
        LEA DX, USER_INPUT_STRING + 2
        MOV AH, 09H
        INT 21H
    
        LEA DX, BREAKLINE
        MOV AH, 09H
        INT 21H
    
        MOV AX, 4C00H
        INT 21H
    END
    

    The only way to avoid the square brackets, I see in the use of LODSB and MOVSB:

    .MODEL SMALL
    .STACK 100H
    
    .DATA
        INPUT_STRING          DB 13,10,"Enter string: $"
        USER_INPUT_STRING     DB 80, 0, 80 DUP('$')
        BREAKLINE             DB 13, 10, "$"
    
    .CODE
    main PROC
        MOV AX, @DATA
        MOV DS, AX
        MOV ES, AX
    
        LEA DX,INPUT_STRING
        MOV AH,09H
        INT 21H
    
        LEA DX, USER_INPUT_STRING
        MOV AH, 0AH
        INT 21H
    
        LEA DX, BREAKLINE
        MOV AH, 09H
        INT 21H
    
        CALL swap
    
        LEA DX, USER_INPUT_STRING + 2
        MOV AH, 09H
        INT 21H
    
        LEA DX, BREAKLINE
        MOV AH, 09H
        INT 21H
    
        MOV AX, 4C00H
        INT 21H
    main ENDP
    
    swap PROC
        LEA DI, USER_INPUT_STRING + 2
        MOV AL, USER_INPUT_STRING + 1
        MOV AH, 0
        SUB AL, 1
        ADD DI, AX
        MOV SI, DI
        LODSB
        MOV AH, USER_INPUT_STRING + 2
        XCHG AL, AH
        STOSB
        MOV USER_INPUT_STRING + 2, AH
        RET
    swap ENDP
    
    END main
    

    In EMU8086 and in TASM (not in MASM) you can also use the special preprocessor arithmetic: USER_INPUT_STRING + 2 + BX - 1:

    .MODEL SMALL
    .STACK 100H
    
    .DATA
        INPUT_STRING          DB 13,10,"Enter string: $"
        USER_INPUT_STRING     DB 80, 0, 80 DUP('$')
        BREAKLINE             DB 13, 10, "$"
    
    .CODE
    main PROC
        MOV AX, @DATA
        MOV DS, AX
        MOV ES, AX
    
        LEA DX,INPUT_STRING
        MOV AH, 09H
        INT 21H
    
        LEA DX, USER_INPUT_STRING
        MOV AH, 0AH
        INT 21H
    
        LEA DX, BREAKLINE
        MOV AH, 09H
        INT 21H
    
        CALL swap
    
        LEA DX, USER_INPUT_STRING + 2
        MOV AH, 09H
        INT 21H
    
        LEA DX, BREAKLINE
        MOV AH, 09H
        INT 21H
    
        MOV AX, 4C00H
        INT 21H
    main ENDP
    
    swap PROC
        MOV AH, USER_INPUT_STRING + 2
        MOV BL, USER_INPUT_STRING + 1
        MOV BH, 0
        MOV AL, USER_INPUT_STRING + 2 + BX - 1
        MOV USER_INPUT_STRING + 2, AL
        MOV USER_INPUT_STRING + 2 + BX - 1, AH
        RET
    swap ENDP
    
    END main
    

    All programs change the content of the string. To undo this, you have to call swap a second time. It is up to you to incorporate the second part.