Search code examples
assemblyx86yasm

How to skip word in YASM (8086)


I've been working on the project. The main goal is to calculate how many words do not contain letters 'B' nor 'C'. Given file has [0;1000] lines. Every line contains 6 columns.

he first two columns contain string with [1; 20] characters. Characters could be letters, numbers, and whitespaces.

3-5 columns contain integers in the range [-100; 100]. 6th column contain real numbers in range [-9.99; 9.99] with only two digits after decimal point.

Each section I separated by a semicolon ';'.

FILE EXAMPLE:

helloA;lB;lC;lD;lE;lF
A11;bas morning;0;0;5;1.15
B12; Hello WoRlD;-100;11;78;1.33
B11;table;10;0;55;-2.44
C1;OakWood;0;8;17;3.77

TASK: calculate how many words (word is one or more symbols without ' '(space)) in the first two columns do not contain letters 'B' or 'C'. And print that integer number.

I have dealt with the most part of the task. I already did File's name reading from command line, reading the file, priting the integer out. But I have stuck on one thing. I don't really get it how to check every word one by one. I almost every time get a wrong answer.

Input: ( a A a a aba aca;BA A C BA a;1;1;1;1.00) - without brackets.
Output: 6

MY CODE SO FAR

org 100h

%include 'yasmmac.inc'

section .text

    startas:
        macPutString 'Write outpu file name', crlf, '$'
        
        ; Reading file from command line
        .commandLine:
            mov bx, 82h
            mov si, 0h
            jmp .checkInputFile

        ; Turns it into ASCIIZ
        .checkInputFile:
            mov cl, [bx+si]
            cmp cl, 20h
            jl .addZero
            inc si
            jmp .checkInputFile
        
        .addZero:
            mov byte [bx+si], 0h
            xor si, si
        
            ; Saving writing file
        mov al, 128         
        mov dx, writingFile
        call procGetStr     
        macNewLine
        
        ; Open reading file
        mov dx, bx
        call procFOpenForReading
        jnc .writingFileIsOpened
        macPutString 'Error while opening reading file', '$'
        exit
        
        ; Atidarome rasymo faila
        .writingFileIsOpened:
            mov [readingDescriptor], bx
            mov dx, writingFile
            call procFCreateOrTruncate
            jnc .openWritingFile
            macPutString 'Error while opening writing file', '$'
            jmp .writingError
        
        ; Save writing descriptor
        .openWritingFile:
            mov [writingDescriptor], bx
            
            
        ; Reads first line
        call procReadLine
    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        ; Main loop
        .whileNotEndOfFile:
            xor di, di
            xor si, si
            call procReadLine
            
            ; Check first two columns
            ;mov al, ';'

        mov di, line
        mov al, [di]
        cmp al, ' '
        je .nextWord
        cmp al, ';'
        je .nextWord
            
            ; Checking words
            .checkWord:
                mov al, [di]
                inc di
                
                cmp al, byte 'B'
                je .nextWord
                cmp al, byte 'b'
                je .nextWord
                cmp al, byte 'C'
                je .nextWord
                cmp al, byte 'c'
                je .nextWord
                
                cmp al, byte ' '
                je .addNumber
                cmp al, byte ';'
                je .semicolon
                jmp .checkWord

            .nextWord:
                call procNextWord
                jmp .checkWord

            .semicolon:
                call procAddNumber
                inc si
                cmp si, 0x2
                je .skipLine
                jmp .nextWord

            .addNumber:
                call procAddNumber
                jmp .nextWord
            
            ; If this is not the end of file, repeat loop
            .skipLine:
            cmp [readLastLine], byte 0
            je .whileNotEndOfFile
            
            ; Hexadecimal convertion to decimal
           mov dx, lineCount
           mov ax, [lineCount]
           call procUInt16ToStr
           call procPutStr
           macNewLine
           mov si, dx


           .writingToFile:
           lodsb
           cmp al, 0
           jne .writingToFile
           sub si, dx
           lea cx, [si-1]
           mov bx, [writingDescriptor]
           mov ah, 40h
           int 21h

        
        
        ; Closing Files
        .end:
            mov bx, [writingDescriptor]
            call procFClose
        
        .writingError:
            mov bx, [readingDescriptor]
            call procFClose
        
        macPutString 'Program ends', crlf, '$'

        exit
        
%include 'yasmlib.asm'

; void procReadLine()
; Read line to buffer ‘eilute’
procReadLine:
    push ax
    push bx
    push cx
    push si
    
    mov bx, [readingDescriptor]
    mov si, 0


    .loop:
        call procFGetChar
    
        ; End if the end of file or error
        cmp ax, 0
        je .endOfFile
        jc .endOfFile
        
        ; Putting symbol to buffer
        mov [line+si], cl
        inc si
    
        ; Check if there is \n?
        cmp cl, 0x0A
        je .endOfLine
    
        jmp .loop
        
        
    .endOfFile:
        mov [readLastLine], byte 1
    .endOfLine:
    
    mov [line+si], byte '$'
    mov [lineLenght], si
    
    pop si
    pop cx
    pop bx
    pop ax
    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
procAddNumber:
    push si
    push ax
    push bx
    push cx
    push dx
    
    ;lineCount++
    mov ax, word [lineCount]
    inc ax
    mov [lineCount], ax
    
    pop dx
    pop cx
    pop bx
    pop ax
    pop si
    ret

procNextWord:

    .loop:
        inc di
        mov al, [di]
        cmp al, byte ' '
        je .loop
        jmp .t

    .t:
        cmp al, byte ';'
        je .t2
        jmp .return

    .t2:
        inc di
        mov al, [di]
        cmp al, byte ' '
        je .t2
        jmp .return

    .return: 
        ret


section .data
        
    readingDescriptor:
        dw 0000
        
    writingFile:
        times 128 db 00
        
    writingDescriptor:
        dw 0000
        
    readLastLine:
        db 00
        
    line:
        db 64
        times 66 db '$'
        
    lineLenght:
        dw 0000
    
    lineCount:
        times 128 db 00

GITHUB: yasmmac.inc/yasmlib.asm

Any help will be appreaciated.


Solution

  • Completely starting over on the thinking process that is needed to solve the main task, I came up with the following:

    • Before checking the character in a word, I skip all the leading whitespace (if present at all)
    • If the leading whitespace ends with a semicolon, it is rather the trailing whitespace from the last word in the current column
    • A word ends when finding a space or a semicolon
    • .checkWord does not early-out on finding an invalid character {BbCc}, but sets a flag to 0
    ; Main loop
    .whileNotEndOfFile:
      call procReadLine
      mov  si, 2       ; Do 2 columns
      mov  di, line
    .skipSpaces:
      mov  al, [di]
      inc  di
      cmp  al, ' '
      je   .skipSpaces
      cmp  al, ';'
      je   .q3         ; It's trailing whitespace
      dec  di
    .checkWord:
      mov  bx, 1       ; Assuming it will be a 'good' word
    .q1:
      mov  al, [di]
      inc  di
      cmp  al, ' '
      je   .q2
      cmp  al, ';'
      je   .q2
      or   al, 32      ; LCase
      cmp  al, 'b'
      jb   .q1
      cmp  al, 'c'
      ja   .q1
      xor  bx, bx      ; One or more invalid chars in current word
      jmp  .q1
         
    .q2:
      add  [lineCount], bx  ; BX=[0,1] Counting the 'good' words
      cmp  al, ';'
      jne  .skipSpaces
    .q3:
      dec  si          ; Next column ?
      jnz  .skipSpaces
    .skipLine:
      cmp  [readLastLine], byte 0
      je   .whileNotEndOfFile
    

    The label lineCount is no longer particularly good for counting valid words, wouldn't you say?