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.
CodePudding user response:
mov al, [di] cmp al, ' ' * je .nextWord * cmp al, ';' * je .nextWord * .checkWord: mov al, [di] inc di
You are losing characters from the string!
Consider eg. "mouse bat" where .checkWord will fetch the space character and leave DI pointing at the "b", but then procNextWord starts by incrementing DI, effectively erasing that "b" from inspection. The rest of the program only sees "at" and thinks it's a 'good' word.
procNextWord:
dec di ; Correcting DEC
.t1:
inc di
mov al, [di]
cmp al, ' '
je .t1
cmp al, ';'
jne .return
.t2:
inc di
mov al, [di]
cmp al, ' '
je .t2
.return:
ret
If you apply the proposed correction, then also change the lines that I marked with asterisks and write:
cmp al, ' '
je .nextWordEx
cmp al, ';'
je .nextWordEx
...
.nextWordEx:
inc di
.nextWord:
call procNextWord
jmp .checkWord
[edit]
When you found an unsuitable character in a word, you need to skip the remainder of that word and that is not something the procNextWord was build for! You need another code:
cmp al, 'B'
je .skipRemaining
cmp al, 'b'
je .skipRemaining
cmp al, 'C'
je .skipRemaining
cmp al, 'c'
je .skipRemaining
cmp al, ' '
je .addNumber
cmp al, ';'
je .semicolon
jmp .checkWord
.skipRemaining:
call procSkipRemaining
jmp .checkWord
...
procSkipRemaining:
mov al, [di]
cmp al, " "
je .return
cmp al, ";"
je .return
inc di
jmp procSkipRemaining
.return:
ret
CodePudding user response:
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 ; UCase
cmp al, 'B'
jb .q1
cmp al, 'C'
ja .q1
mov bx, 0 ; 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?