Search code examples
assemblyemu8086microprocessors

Reverse word letters of a sentence with keeping same word order as entered in emu8086


I need to write a program in assembly language with emu8086, that takes a sentence(include space/blank) and give output with the following conditions:

  1. displays the text in the same word order as entered, but with the letters in each word reversed.
  2. Example "hello world" input give the output: "olleh dlrow"

I tried with the following code:

.MODEL SMALL
.STACK 100H
.DATA

; The string to be printed
STRING DB 'This is a sample string', '$'

.CODE
MAIN PROC FAR
MOV AX,@DATA
MOV DS,AX

; call reverse function
CALL REVERSE

; load address of the string
LEA DX,STRING

; output the string
; loaded in dx
MOV AH, 09H
INT 21H

; interrupt to exit
MOV AH, 4CH
INT 21H

MAIN ENDP
REVERSE PROC
    ; load the offset of
    ; the string
    MOV SI, OFFSET STRING

    ; count of characters of the;
    ;string
    MOV CX, 0H

    LOOP1:
    ; compare if this is;
    ;the last character
    MOV AX, [SI]
    CMP AL, '$'
    JE LABEL1

    ; else push it in the;
    ;stack
    PUSH [SI]

    ; increment the pointer;
    ;and count
    INC SI
    INC CX

    JMP LOOP1

    LABEL1:
    ; again load the starting;
    ;address of the string
    MOV SI, OFFSET STRING

        LOOP2:
        ;if count not equal to zero
        CMP CX,0
        JE EXIT

        ; pop the top of stack
        POP DX

        ; make dh, 0
        XOR DH, DH

        ; put the character of the;
        ;reversed string
        MOV [SI], DX

        ; increment si and;
        ;decrement count
        INC SI
        DEC CX

        JMP LOOP2

                
    EXIT:
    ; add $ to the end of string
    MOV [SI],'$ '
    RET
        
REVERSE ENDP
END MAIN

But this reverses the whole sentence (don't keep the same word order). Like "hello world" input gives "dlrow olleh" output.

Please suggest how can I fix this?


Solution

  • You correctly used procedure REVERSE to reverse the entire STRING. When you need to reverse each lexical word of the STRING separately, you should similarly split up the task: parse the input string to words and apply a subprocedure ReverseWord to each such word.

    Dividing the task to smaller subprocedures makes is better apprehensible and it's easier to debug. You can try to optimize it later, if necessary.

    REVERSE PROC                ; Reverse words in STRING.
              LEA SI,[STRING]
              CLD               ; LODSB will parse forward.
    NextWord: MOV DI,SI         ; Let SI=DI=at the first char of the word.
    NextChar: LODSB             ; Load AL from [SI], increment SI.
              CMP AL," "        ; Search for white-space terminator.
              JBE WordEnd
              CMP AL,"$"        ; $ terminates the word, too.
              JE StringEnd
              JMP NextChar      ; Repeat when the word is not terminated yet.
    WordEnd:  CALL ReverseWord  ; Reverse the word between DI and SI.
              JMP NextWord
    StringEnd:CALL ReverseWord  ; Reverse the last word between DI and SI.
              RET               ; All words are reversed in situ.
            ENDP
    
    ReverseWord PROC            ; Reverse the word between DI and SI-1.
         PUSHAW                 ; Do not clobber any register.
          DEC SI                ; Let SI=behind the last char of the word.
          MOV CX,SI
          SUB CX,DI             ; Let CX=number of chars in the word.
          SHR CX,1              ; Divide CX in half, ignore remainder.
          JZ Done               ; Do nothing when the word is 1 char or less.
    Again:DEC SI                ; Let SI=at the last char of the word.
          MOV AL,[SI]           ; Load AL with the last char.
          MOV DL,[DI]           ; Load DL with the first char.
          MOV [SI],DL           ; Swap the first and the last chars.
          MOV [DI],AL
          INC DI
          LOOP Again            ; Repeat with the inner chars.
    Done:POPAW                  ; Restore all registers.
         RET                    ; The word between DI..SI was reversed.
        ENDP
    

    The inner subprocedure ReverseWord is used twice, string terminator $ remains unclobbered in situ. Notice that the number of character exchanges is half of the word size, and when the word size is odd, the middle character stays in its original position (in situ).