Search code examples
assemblyreverseuppercaselowercaseemu8086

Assembly emu8086, reversing a string


I am trying to make a program where the user have to enter a string and get an reversed output. Moreover, it should change all lowercase letters to uppercase and uppercase to lowercase. I've already done program where you can enter 1 character. My next goal is to get as many characters as I want.

I did some research and came up with this code:

org 100h
include emu8086.inc
.DATA
  STR1 DB 0DH,0AH, 'Input: $'
  STR2 DB 0DH,0AH, 'Output: $'
  nl db 0dh,0ah,'$' 

.CODE
  START:
    MOV AX, @DATA
    MOV DS, AX
    cmp al, 0x41h
    JGE IsInLowerCaseRange



  Disp:
    LEA DX,STR1
    MOV AH,09H
    INT 21H

    MOV CL,00
    MOV AH,01H

  Read:
    INT 21H

    MOV BL,AL

    PUSH BX
    inc cx
    CMP AL,0DH

    JZ DISPLAY
    JMP READ

  Display:
    LEA DX,STR2
    MOV AH,09H
    INT 21H

    lea dx, nl
    mov ah,09h
    int 21h

  ANS:
    MOV AH,02H
    POP BX
    MOV DL,BL
    INT 21H
    LOOP ANS

  IsInLowerCaseRange:
    cmp al, 0x5Ah
    jle DisplayLowerCaseLetter
    cmp al, 0x61h
    jge IsInUpperCaseRange
    jmp NotALetter


  DisplayLowerCaseLetter:
    add al, 0x20h
    mov ah, 0xEh
    int 10h
    jmp exit


  IsInUpperCaseRange:
    cmp al, 0x7Ah
    jle DisplayUpperCaseLetter
    jmp NotALetter


  DisplayUpperCaseLetter:
    sub al, 0x20h
    mov ah, 0xEh
    int 10h
    jmp exit 


  NotALetter:
    printn
    print "The input character is not a letter."
    exit:
    hlt 

.EXIT
END  START

Now I am getting a wrong output. For example if you enter Hello it will return olleHh. I am completely confused since I can't figure out my error. Also, I am new in Assembly. The output that I expect is OLLEh.

Working Code:

org 100h
include emu8086.inc


.DATA
   STR1 DB 0DH, 0AH, 'Input: $'
   STR2 DB 0DH, 0AH, 'Output: $'
   Nl DB 0Dh, 0Ah,'$' 


.CODE
START:
    MOV AX, @DATA
    MOV DS, AX


DISP:
    LEA DX,STR1
    MOV AH,09H
    INT 21H
    MOV CL,00
    MOV AH,01H


READ:
    INT 21H
    MOV BL, AL
    PUSH BX
    INC CX
    CMP AL, 0DH
    JZ DISPLAY
    CMP AL, 'A'                 ; < then A  
    JB  NotALetter
    CMP AL, 'Z'                 ; > then Z 
    JA  AGAIN                   ; repeat again
    JMP CONTINUE1


AGAIN:  
    CMP AL, 'a'                 ; < then a
    JB  NotALetter  
    CMP AL, 'z'                 ; > then z 
    JA  NotALetter       


CONTINUE1:
    JMP READ


DISPLAY:
    LEA DX, STR2
    MOV AH, 09h
    INT 21H
    LEA DX, NL
    MOV AH, 09h
    INT 21h
    POP BX                      ; pop enter key


ANS:
    MOV AH, 02h
    POP BX                      ; pop the character 
    CMP BL, 'a'                 ; check if its in upper case
    JB  toLower                 ; if yes then jmp to toLower 
    SUB BL, 32                  ; if not in upper case then convert to upper case
    JMP CONTINUE2


toLower:
    ADD BL, 32                  ; convert to lower case
    ; Probably have to subtract 32 if BL = 20h


CONTINUE2:
    MOV DL, BL
    INT 21H
    LOOP ANS  
    JMP EXIT                    ; if everything is fine jmp to exit                 


NotALetter:        
    printn
    print "The input character is not a letter."    


EXIT:
    hlt 

.EXIT
END  START

Solution

  • You are making it complex.

    First you display all the letters of your string in reverse order with the following code:

    ANS:
    MOV AH,02H
    POP BX
    MOV DL,BL
    INT 21H
    LOOP ANS
    

    and then you try to flip the cases with the following code:

    IsInLowerCaseRange:
       cmp al, 0x5Ah
       jle DisplayLowerCaseLetter
       cmp al, 0x61h
       jge IsInUpperCaseRange
       jmp NotALetter  
    
    DisplayLowerCaseLetter:
        add al, 0x20h
        mov ah, 0xEh
        int 10h
        jmp exit
    
    
      IsInUpperCaseRange:
        cmp al, 0x7Ah
        jle DisplayUpperCaseLetter
        jmp NotALetter
    
    
      DisplayUpperCaseLetter:
        sub al, 0x20h
        mov ah, 0xEh
        int 10h 
    

    Problem is with using 0EH service of INT 10H

    Why do you get that extra h letter at the end of your output string ?

    You are using INT 10h which is used for video services and the service 0EH of INT 10h writes the specified character in AL to the current cursor position. Since the last character in AL was capital H in your example and which was flipped to lower case h by your code. That is where you get that extra h at the end of your output string.

    Why don't you get all the letters flipped ?

    Since the service 0EH of INT 10h writes only one character to the screen (not the string) you get only H to be flipped.

    Solution:

    You could have simply flipped the cases and displayed the reverse string in one go and that without using INT 10h.

    Here is a simple code which is well documented and that does the job:

     org 100h
    .DATA
    
      str1 db 10,13, 'Input: $'
      str2 db 10,13, 'Output: $'    
      errMsg db 10,13, 'The input character is not a letter.$'  
    
    .CODE
    
      START:    
    
        mov ax, @DATA
        mov ds, ax
    
        mov dx, offset str1
        mov ah, 09h
        int 21h
    
        mov cl,00
        mov ah,01h 
    
        mov bx, '#'   ; store some random character 
                      ; into stack to remeber when to stop
        push bx       ; poping the character while diplaying
    
      Read: 
    
        int 21h
    
        cmp al, 13    ; check if enter key is pressed
    
        je DISPLAY    ; if yes then display the letters if any
    
        cmp al, 'A'     ; check if ASCII value of inputted charater is less than ASCII value of capital A  
        jb  NotALetter  ; if yes then print "no a letter"
    
        cmp al, 'Z'     ; check if ASCII value of inputted charater is not greater than ASCII value of capital Z 
        jna  letterFound  ; if not then continue 
    
        cmp al, 'a'     ; check if ASCII value of inputted character is less than ASCII value of small a 
        jb  NotALetter  ; if yes then print "no a letter"
    
        cmp al, 'z'     ; check if ASCII value of inputted character is greater than ASCII value of small z 
        ja  NotALetter  ; if not then continue 
    
        letterFound:
    
        mov bl, al
    
        push bx         ; store the letter in stack
    
        jmp READ
    
      Display:
    
        mov dx,offset str2
        mov ah,09h
        int 21h
    
      ANS:
    
        pop bx
    
        cmp bl, '#'   ; check if no more letter are available in stack
        je exit       
    
        mov ah, 02h
        cmp bl, 'a'   ; check if the letter is in upper case
        jb  toLower   ; if yes then jmp to toLower 
    
        sub bl, 32    ; if not in upper case then convert to upper case
        jmp continue
    
      toLower:
    
        add bl, 32  ; convert to lower case
    
      continue:
    
        mov dl, bl
        int 21h
        jmp ans
    
      NotALetter: 
    
        mov ah, 09h
        mov dx, offset errMsg  ; display error message
        int 21h
    
      exit:
    
        mov ah, 04ch
        int 21h
    
    END  START
    

    And as @Ped7g said you should use comment in your program because that explain what you are trying to do in your program and makes it easy for people to debug it.