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:
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?
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).