-1

I am trying to reverse the string but simultaneously change each character to its next corresponding letter in the alphabet but must be the opposite capitalization as well. For instance, when the user enters "Test" the output should be "UTFu".

How can I modify my code to achieve this?

INCLUDE Irvine32.inc
INCLUDELIB Irvine32.lib
 
.data
    buffer byte 128 dup(0)
    msg1   byte  "Enter a string of at most 128 characters:", 0dh, 0ah, 0
    msg2   byte  " Here it is in LOWERCASE and in reverse order: ", 0dh, 0ah, 0
    msg3   byte   0dh, 0ah, " There are ",0
    msg4   byte  " lower-case characters ", 0dh, 0ah, 0
    countLower byte 0
 
.code
    main PROC
 
    mov ecx, 0
    mov eax, 0
    mov edx,OFFSET msg1
    call WriteString

    read_again:
       cmp ecx, 128
       ja endread

    call ReadChar
    cmp al, 0Dh
    je display
    cmp al, 61h
    jae test_lower
    cmp al, 41h
    jb store
    cmp al, 5Ah
    ja store
    add al, 20h
    inc countLower
    ja store

   test_lower :
    cmp al, 7Ah
    ja store
    sub al, 20h

   store:
    push eax
    inc ecx
    jmp read_again

   endread:
    lea esi, buffer

   display :
    jecxz quit
    mov edx, OFFSET msg2
    call WriteString

   again: 
    pop eax
    call WriteChar
    loop again
    mov edx, OFFSET msg3
    call WriteString
    movzx eax,countLower
    call WriteDec
    mov edx, OFFSET msg4
    call WriteString

   quit:
 
   exit
   main ENDP
END main
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 2
    What does your code do now? – prl Nov 07 '20 at 01:34
  • If you can assume alphabetic input, can probably do it with `bswap eax`, `add eax, 0x01010101` to increment by 1. Extract the sign bit with `mov ecx, eax` / `and ecx, 0x20202020`, and make all lower-case in the original with `or eax, 0x20202020`. Then check for being outside the ASCII range and if so subtract 26. (`pcmpgtb` SIMD is possible: [Converting Uppercase to Lowercase in Assembly issue](https://stackoverflow.com/q/40366031)). When done, re-apply the sign bit and flip by XORing the saved case bits into the modified characters, which all have that bit set. – Peter Cordes Nov 07 '20 at 05:46
  • Oh, your example probably didn't mean the input is *always* 4 bytes. You can do 4 bytes at a time, though, or 16 with a convenient SSSE3 byte-reverse. – Peter Cordes Nov 07 '20 at 05:47
  • Oops, meant to link [How to access a char array and change lower case letters to upper case, and vice versa](https://stackoverflow.com/a/35936844) for the case-flip – Peter Cordes Nov 08 '20 at 03:11

1 Answers1

1

...change each character to its next corresponding letter in the alphabet but must be the opposite capitalization as well.

Applying this to the ASCII character sets means we need next conversion:

      Z                            z
IN  ...ABCDEFGHIJKLMNOPQRSTUVWXYZ...abcdefghijklmnopqrstuvwxyz...
OUT ...bcdefghijklmnopqrstuvwxyza...BCDEFGHIJKLMNOPQRSTUVWXYZA...

The first step will be to classify the input. Separate the uppercase and the lowercase and all the rest.

For the uppercase characters A through Y, your next step will be to add 1 to change to the next letter and add 32 to change the case. For Z, that needs the wraparound, you place it temporarily right before A and then act as before.

DoUpperCase:
  cmp  al, 'A'
  jb   Store
  cmp  al, 'Z'
  ja   DoLowerCase
  jb   .Convert     ; A-Y  --> b-z
  mov  al, 'A'-1
.Convert:
  add  al, 'b'-'A'  ; EQ (1 + 32)
  jmp  Store

For the lowercase characters a through y, your next step will be to add 1 to change to the next letter and subtract 32 to change the case. For z, that needs the wraparound, you place it temporarily right before a and then act as before.

DoLowerCase:
  cmp  al, 'a'
  jb   Store
  cmp  al, 'z'
  ja   Store
  jb   .Convert     ; a-y  --> B-Z
  mov  al, 'a'-1
.Convert:
  sub  al, 'a'-'B'  ; EQ (1 - 32)
Store:
  push eax
  inc  ecx
  jmp  read_again
Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • Seems to me it would be easier to force all letters to the same case so you only need to implement one form of the alphabet-wrapping add, then restore+flip the cases. [How to access a char array and change lower case letters to upper case, and vice versa](https://stackoverflow.com/a/35936844) shows efficient case-flip (along with checking for non-ASCII). Forcing to lower-case makes inversion happen when applying the old case-bits with XOR. Separating upper and lower is the more "pedestrian" / beginner approach, I guess, but less elegant. – Peter Cordes Nov 08 '20 at 03:15