1

I can't seem to find a way to add a vowel counter to my program. The program must use Irvine32.inc in order to be valid.

INCLUDE Irvine32.inc
ExitProcess PROTO, dwExitCode:DWORD

.data

msg1 BYTE "Enter any string of your choice: ",0
msg2 BYTE "The number of words in the input string is: ",0
msg3 BYTE "The output string is: ",0
string BYTE 50 dup(?)
vowelc BYTE ?


.CODE
main PROC
    mov edx,offset msg1     ;;PROMPT FOR STRING
    call writestring
    mov ecx,50
    mov edx,offset string   ;;LOAD THE ADDRESS OF THE STRING
    call readstring         ;;READ STRING
    call crlf               ;;NEWLINE
    lea esi,string          ;;STARTING ADDRESS OF THE STRING INTO ESI
repeet:
    mov al,[esi]            ;;LOAD ONE CHARACTER INTO AL
    cmp al,0                ;;CHECK AL==0?
    je eos                  ;;IF AL==0, GOTO EOS BECAUSE IT SAYS END OF STRING
    cmp al,20h              ;;CHECK AL==20?
    jne ahead               ;;IF AL IS NOT SPACE GOTO AHEAD             
    jmp nochange            ;;JUMP TO NOCHANGE
ahead:
    cmp al,61h              ;;CHECK AL==61? IF LOWER LIMIT OF LOWER CASE
    jl checklimit           ;;IF THE CHAR IS < 61, IT CAN BE A CAPITAL LETTER OR SOME OTHER CHAR. HENCE GOTO CHECKLIMIT
    cmp al,7ah              ;;CHECK AL==7A?
    jg nochange             ;;IF ANY OTHER CHAR, MAKE NO CHANGE
    sub al,20h              ;;CONVERT LOWERCASE TO UPPERCASE
    mov [esi],al            ;;SAVE TO STRING
    jmp nochange            ;;GOTO NOCHNAGE
checklimit:
    cmp al,5ah              ;;CHECK AL==5A?
    jg nochange             ;;IF CHAR > Z, MAKE NO CHANGE

    cmp al,41h              ;;CHECK AL==41?
    jl nochange             ;;IF CHAR < A, MAKE NO CHANGE

    add al,20h              ;;IF CHAR IS FROM A - Z,CONVERT IT TO LOWERCASE
    mov [esi],al            ;;STORE IT TO STRING
nochange:
    inc esi                 ;;INCREMENT ESI TO GET NEXT CHAR
    jmp repeet              ;;REPEAT TILL END OF THE STRING
eos:
    mov edi, OFFSET string
    mov al,'A'
    mov ecx, LENGTHOF string

    mov edx,offset msg3     ;;DISPLAY PROMPT3 MESSAGE
    call writestring
    mov edx,offset string   ;;DISPLAY CHANGED STRING
    call writestring
    call crlf
INVOKE ExitProcess, 0       ;;EXIT
main ENDP
END MAIN

Somehow I have to find a way to add a vowel counter into this program without messing anything up but I don't know how.

I tried looking for options in my book but I couldn't find any related code.

I did also try to look for info on other sites but nobody seems to be able to help me.

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • Well, the trivial way would be to just add a bunch of `cmp` instructions checking for each vowel. I trust you can increment a counter. – Jester Dec 15 '22 at 02:15
  • [Where can the code be more efficient for checking if an input character is a vowel?](https://stackoverflow.com/q/36121970) shows a way to check for a character being a vowel, once you know it's alphabetic. It works by using `bt` on a bitmap in a register, with the index being the letter's position in the alphabet (e.g. `(c|0x20) - 'a'` once you've verified you have an alphabetic character.) Since that gets the result in CF, you can `adc ebx, 0` or whatever register you have a vowel count in. – Peter Cordes Dec 15 '22 at 02:50
  • 2
    Handling "y" is best done by ignoring the rules of the English language and either always counting it or never. Trying to actually do it properly is basically impossible since there's no easy pattern to it. – puppydrum64 Dec 15 '22 at 13:25

1 Answers1

2
sub al,20h      ;;CONVERT LOWERCASE TO UPPERCASE
mov [esi],al    ;;SAVE TO STRING
...
add al,20h      ;;IF CHAR IS FROM A - Z,CONVERT IT TO LOWERCASE
mov [esi],al    ;;STORE IT TO STRING

There are 2 places in the existing program (that apparantly you want to keep working) where you store an alphabetical character case-converted back into the string. Those are the spots where you could test for vowels and possibly increment the counter.

sub  al, 20h       ; UCase
mov  [esi], al
call IsVowel       ; After converting to uppercase
...
call IsVowel       ; Before converting to lowercase
add  al, 20h       ; LCase
mov  [esi], al

Carefully chosing the right spot, allows to write an IsVowel code that only has to treat uppercase characters:

IsVowel:
  cmp  al, 'A'
  je   Yes
  ...
  cmp  al, 'U'
  jne  No
Yes:
  inc  vowelc
No:
  ret

The existing code can be improved a lot. eg. Don't use the signed conditionals on bytes that are ASCII codes. And both character cases can be detected together and toggled with xor al, 32.

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • 1
    The fun way is an immediate bitmap with `bt`, as in [Where can the code be more efficient for checking if an input character is a vowel?](https://stackoverflow.com/q/36121970). Since that gets the result in CF, you can `adc ebx, 0` or whatever you're counting vowels. `(c|0x20) - 'a'` is your index into the alphabet; you'd normally have that as part of detecting alphabetic or not, e.g. as part of an ASCII case-flip ([How to access a char array and change lower case letters to upper case, and vice versa](https://stackoverflow.com/a/35936844)) – Peter Cordes Dec 15 '22 at 02:53