Search code examples
assemblymasmirvine32masm32

MASM loop counter only displays '+0' (irvine32)


I have a script that is almost done. I am struggling to finish the word counter. In this case I am counting each instance of a space and assuming that means it is the end of a word.

The 'totalWords' variable is initialized to 0 and incremented each time a ' ' is found in a string.

However, the output is always '+0' whenever tested. I know the rest of the script works because it transforms the case of the letters successfully.

What is the best practice to increment a variable and display it?

INCLUDE Irvine32.inc

.data
    source BYTE 40 DUP (0)
    byteCount DWORD ?
    target BYTE SIZEOF source DUP('#')
    sentencePrompt BYTE "Please enter a sentence: ",0
    wordCountPrompt BYTE "The number of words in the input string is: ",0
    outputStringPrompt BYTE "The output string is: ",0
    totalWords DWORD 0                                                      ; SET TOTALWORDS VARIABLE TO 0 INITIALLY
    one DWORD 1
    space BYTE " ",0

.code
main PROC
    mov edx, OFFSET sentencePrompt
    call Crlf
    call WriteString
    mov edx, OFFSET source
    MOV ecx, SIZEOF source
    call ReadString
    call Crlf
    call Crlf
    call TRANSFORM_STRING
    call Crlf
    exit
main ENDP

TRANSFORM_STRING PROC
    mov esi,0
    mov edi,0
    mov ecx, SIZEOF source

    transformStringLoop:
        mov al, source[esi] 
            .IF(al == space)                
                inc totalWords                  ; INCREMENT TOTALWORDS DATA
                mov target[edi], al
                inc esi
                inc edi
            .ELSE
                .IF(al >= 64) && (al <=90)
                    add al,32
                    mov target[edi], al
                    inc esi
                    inc edi
                .ELSEIF (al >= 97) && (al <=122)
                    sub al,32
                    mov target[edi], al
                    inc esi
                    inc edi
                .ELSE
                    mov target[edi], al                 
                    inc esi
                    inc edi
                .ENDIF
            .ENDIF
        loop transformStringLoop
        mov edx, OFFSET wordCountPrompt
        call WriteString
        mov edx, OFFSET totalWords                              ; DISPLAY TOTALWORDS
        call WriteInt
        call Crlf
        mov edx, OFFSET outputStringPrompt
        call WriteString
        mov edx, OFFSET target
        call WriteString
        ret
TRANSFORM_STRING ENDP
END main

Solution

  • This part is incorrect:

    mov edx, OFFSET totalWords                              ; DISPLAY TOTALWORDS
    call WriteInt
    

    WriteInt doesn't expect an offset in edx; it expects the actual integer value in eax. So the code should be:

    mov eax, totalWords                              ; DISPLAY TOTALWORDS
    call WriteInt
    

    Also, your space variable is pointless. You could just write

    .IF(al == ' ')
    

    And your way of counting the number of words sounds a bit broken. A string such as "foo bar" contains only 1 space, but two words. Note that you can't really use number_of_spaces+1 either, because that would give the wrong result for strings like " ", "foo bar" and "foo ".

    You'd probably get better results with something like:

    if (al != ' ' && (esi == 0 || source[esi-1] == ' ')) totalWords++;
    

    That's just some pseudo-code to express the idea. I'll leave it up to you to translate that into x86 assembly.