I have to write a program that would filter text lines from the input file. Each line is divided into six columns. Columns are separated from each other by a semicolon.
I implemented 3 filters:
- Second column has to contain no
u
orv
letters. - Third column has to contain a number so that it's sum of digits is equal to
7
. - Last column has to contain number that belongs to the intervar of
[2.34, 4.50]
. Numbers are known to always be two decimals.
Here's input file example:
B11;one;16;0;55;2.44
C1;two;43;0;17;3.77
D2;three;47;0;15;5.41
First two lines would pass all of three filters.
I implemented a function that checks if last column numbers belong to the given interval and if numbers do belong to the interval, the function should add them all together (considering that the line also passed two previous filters).
So with input example I am showing here, result should look like this:
B11;one;16;0;55;2.44
C1;two;43;0;17;3.77
6.21
However, my function that checks last column numbers seems to work incorrectly. What could be the problem?
EDIT: procBelongsToInterval
function is updated
;[2.34, 4.50]
procBelongsToInterval
push ax
xor ax, ax
xor si, si
; saving floating point number digits to the buffer (without '.')
.read
mov al, [di]
inc di
cmp al, '-'
je .break
cmp al, '.'
je .read
cmp al, 32
jb .setToZero
mov [doubleNumbers si], al
inc si
jmp .read
; used si as a pointer to the next byte so have to set si to zero again
.setToZero
xor si, si
jmp .first
; checking if number is in the bounds [2.34, 4.50]
.first:
mov al, [doubleNumbers si]
inc si
cmp al, '2'
je .firstBound
cmp al, '3'
je .belongs
cmp al, '4'
je .secondBound
jmp .break
.firstBound:
mov al, [doubleNumbers si]
inc si
cmp al, '3'
jb .break
ja .belongs
mov al, [doubleNumbers si]
inc si
cmp al, '4'
jae .belongs
jb .break
.secondBound:
mov al, [doubleNumbers si]
inc si
cmp al, '5'
ja .break
jb .belongs
mov al, [doubleNumbers si]
inc si
cmp al, '0'
je .belongs
ja .break
; number belongs to the interval
.belongs:
mov [numberBelongsToInterval], byte 1 ; boolean value
mov si, 3
mov [doubleNumbers si], byte 0
mov [bytesRead2], si ; saving number of read bytes
mov dx, doubleNumbers
call procParseInt16 ; Extracts an integer of type int16 from the buffer whose address is DX.
; Function saves result into AX register
add [suma], ax ; Adding sum with value in AX
jmp .end
.break:
mov [numberBelongsToInterval], byte 0
jmp .end
.end:
pop ax
ret
procParseInt16
function:
procParseInt16:
push dx
push cx
push si
push di
mov bx, dx
mov ax, 0
mov si, 0 ; number of digits
mov cl, 0 ; 0 - if nonnegative, 1 - otherwise
; eating spaces:
.leading_spaces:
cmp [bx], byte ' '
jne .next1
inc bx
jmp .leading_spaces
.next1:
cmp [bx], byte 0 ; the end of the string?
jne .next2
jmp .endParsing
.next2:
cmp [bx], byte '-' ; the minus
jne .digits
mov cl, 1 ; negative number
inc bx
.digits:
cmp [bx], byte '0'
jb .lessThanNumeric
cmp [bx], byte '9'
jbe .updateAX
.lessThanNumeric:
jmp .endParsing
.updateAX:
mov dx, 10
mul dx
mov dh, 0
mov dl, [bx]
sub dl, '0'
add ax, dx
inc si
inc bx
jmp .digits
.endParsing:
cmp si, 0 ; empty string?
je .setErrorAndReturn
clc
cmp cl, 1
je .negateAndReturn
jmp .return
.negateAndReturn:
neg ax
jmp .return
.setErrorAndReturn:
stc
.return:
pop di
pop si
pop cx
pop dx
ret
procInt16ToStr
function converts int16 value to string (ASCIIZ)
It does not add .
between numbers. So the program prints 432
after calling the function if we use file example above.
procInt16ToStr:
; Converts value from AX to ASCIIZ (decimal system)
; AX - int16 value
; DX - adress, where the result is placed
push di
push si
push cx
push bx
push dx
mov bx, dx
mov cx, 0
mov si, 0
cmp ax, word 0
jge .next
mov cl, 1
mov [bx], byte '-'
inc bx
neg ax
.next:
mov dx, 0
mov di, 10
div di
add dl, '0'
mov [bx], dl
inc bx
inc si
cmp ax, 0
je .setSign
jmp .next
.setSign:
.reverse:
; inc bx
mov [bx], byte 0 ; asciiz
dec bx
pop dx
push dx
mov di, dx
cmp cl, 1
jne .Ok
inc di
.Ok:
mov ax, si
shr ax, 1
mov cx, ax
cmp cx, 0
je .return
.loopByDigits:
mov al, [di]
mov ah, [bx]
mov [di], ah
mov [bx], al
dec bx
inc di
loop .loopByDigits
.return:
pop dx
pop bx
pop cx
pop si
pop di
ret
CodePudding user response:
In procBelongsToInterval
A.
cmp al, ';' je .setToZero
The 6th column ends with the newline. This should read:
cmp al, 32
jb .setToZero
B.
mov dx, [doubleNumbers] call procParseInt16
DX is supposed to be the address of the buffer that contains the digits. This should read:
mov dx, doubleNumbers
call procParseInt16
C.
mov [doubleNumbers si], byte '$' mov [bytesRead2], si ; saving number of read bytes
- You procParseInt16 uses 0 instead of $ as a terminator. Both codes have to agree.
- SI does not always point behind the digits!
If the dispatcher jumps straight to .belongs then SI will be 1.
If the dispatcher passes through .firstBound then SI will be 2 or 3.
If the dispatcher passes through .secondBound then SI will be 2 or 3.
All of the numbers follow the template X.XX, so I suggest writing:
mov si, 3
mov [doubleNumbers si], byte 0
mov [bytesRead2], si ; saving number of read bytes
In procParseInt16
clc cmp cl, 1 je .negateAndReturn jmp .return
Currently your program does not interpret the carry flag returned by this proc, but if it did you would see that the carry is always set!
Because of where you wrote clc
and because you don't submit negative numbers to this proc (meaning CL=0), the cmp cl, 1
instruction will have set the carry.
My suggestion (test
always clears the carry):
test si, si ; empty string?
stc
jz .return ; Yes, CF=1
test cl, cl ; positive number?
jz .return ; Yes, CF=0
neg ax
clc
.return: