1

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:

  1. Second column has to contain no u or v letters.
  2. Third column has to contain a number so that it's sum of digits is equal to 7.
  3. 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
user10203585
  • 105
  • 6
  • 3
    It's unclear why you `cmp al, ';'` ... if it's the last column it doesn't have a semicolon after it. Also, _"seems to work incorrectly"_ is not a good problem description. Note that since you have `procParseInt16` it would be a lot simpler to do the interval check after you parsed the number. – Jester Dec 20 '22 at 18:54
  • One of the problems were definitely `cmp al, ';'`. Haven't thought about it but fixed it now and the program works with filtering the lines. However, last column numbers addition still don't work. – user10203585 Dec 20 '22 at 19:23
  • 1
    If your `procParseInt16` expects a pointer as the comment says, then you want `mov dx, doubleNumbers` without brackets or `lea dx, [doubleNumbers]` – Jester Dec 20 '22 at 19:38
  • The program prints incorrect sum. It is supposed to be `6.21` but the program gives me `33.86`. That is strange. – user10203585 Dec 20 '22 at 19:51
  • 1
    You did not show those parts so who knows. Use your debugger. – Jester Dec 20 '22 at 19:52
  • 1
    Did you fix the `mov dx, [doubleNumbers]`? Also you do `mov [doubleNumbers+si], byte '$'` but the proc expects a zero not a `$`? – Jester Dec 20 '22 at 20:03
  • I updated the post. Right now there is a function code. I would appreciate if you would take a look. I am using dosbox, it does not have any kind of debugger (as far as I know). That's why it is very difficult to write fully functional program without bugs. – user10203585 Dec 20 '22 at 20:03
  • 2
    There is [dosbox debugger](https://www.vogons.org/viewtopic.php?t=7323) but you can of course just use a standalone one such as turbo debugger. – Jester Dec 20 '22 at 20:06
  • Yes, I fixed both points but the result is still not correct. – user10203585 Dec 20 '22 at 20:08
  • Great, I will have a look into debugger then. – user10203585 Dec 20 '22 at 20:10
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/250561/discussion-between-user10203585-and-jester). – user10203585 Dec 20 '22 at 20:10

1 Answers1

1

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:
Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • Thank you for help. I looked through all of your mentioned points and implemented your corrections in my code. I suppose now that both `procBelongsToInterval` and `procParseInt16` functions should work properly. However, as I write the result to the standart output I convert it back to the string, also put the point symbol between the numbers. I am not sure where is the problem but running the input text I wrote above, the program prints wrong result. I get `4.32` instead of `6.21`. If I print the result after each addition I get `2.96 4.32`. – user10203585 Dec 21 '22 at 11:10
  • I updated my post with one more function (`procInt16ToStr`). It converts `int16` value to a `string`. I am not sure where is the problem of getting wrong sum. – user10203585 Dec 21 '22 at 11:55
  • @user10203585 The *procInt16ToStr* code seems correct (although inefficient with that reversing part). For any further debugging you'll have to provide more of the program. – Sep Roland Dec 24 '22 at 16:32