Home > Mobile >  How to write decimal number by one char to file 8086 YASM
How to write decimal number by one char to file 8086 YASM

Time:11-12

I have a task and I will try to explain it clearly. There is a file with [0; 1000] lines. Each line contains 6 columns.

The 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: count how many lines in the first two sections contain the letters 'B' and 'C'. And print that integer number in the other file.

I did almost all the task, except one thing. I don't know how to print the decimal number in the file. I store this number in memory as hexadecimal. I need to convert that number to decimal and print it into the other file.

I am struggling because there could be 1 good line, but it also could be 1000 good lines. So I need to print 1 character (if the number of good lines is between [0; 9]), but it could be 900 good lines, so then the program has to print 3 characters.

MY CODE

org 100h

%include 'yasmmac.inc'

section .text

    startas:
        macPutString 'Output file:', crlf, '$'
        
            ; Save the writing file's name
        mov al, 128         
        mov dx, writingFile
        call procGetStr     
        macNewLine
        
        ; Open reading file
        mov dx, readingFile
        call procFOpenForReading
        jnc .writingFileOpen
        macPutString 'Error while opening the writing file!', '$'
        exit
        
        ; Open the writing file
        .writingFileOpen:
            mov [readingDescriptor], bx
            mov dx, writingFile
            call procFCreateOrTruncate
            jnc .writingFileSuccessfullyOpened
            macPutString 'Error while opening file for writing!', '$'
            jmp .writingError
        
        ; Sacing writing descriptor
        .writingFileSuccessfullyOpened:
            mov [writingDescriptor], bx
            
            
        ; Read first line
        call procReadLine
        
        ; Main loop
        .untilEndOfFile:
            call procReadLine
            
            ; checking the first two columns
            ;mov al, ';'
            
            ; checking first column
            .firstColumn:
                mov al, [di]
                inc di
                
                cmp al, byte 'B'
                je .skipALine
                cmp al, byte 'b'
                je .skipALine
                cmp al, byte 'C'
                je .skipALine
                cmp al, byte 'c'
                je .skipALine
                
                cmp al, byte ';'
                jne .firstColumn
                
            ; checking second column
            .secondColumn:
                mov al, [di]
                inc di
                
                cmp al, byte 'B'
                je .skipALine
                cmp al, byte 'b'
                je .skipALine
                cmp al, byte 'C'
                je .skipALine
                cmp al, byte 'c'
                je .skipALine
                
                cmp al, byte ';'
                jne .secondColumn
                jmp .addNumber      ; Adding number because line corresponds to filter.
                
            .addNumber:
                call procAddNumber
                
            
            ; If it is not the end of file, jump back to main loop
            .skipALine:
            cmp [readTheLastLine], byte 0
            je .untilEndOfFile
            
            ; Writing to file (number, how many good lines)
            ; **I cant do this part**
            mov bx, [writingDescriptor]
            mov cx, 2h
            mov dx, lineCount
            mov ah, 40h
            int 21h
        
        
        ; Closing Files
        .end:
            mov bx, [writingDescriptor]
            call procFClose
        
        .writingError:
            mov bx, [readingDescriptor]
            call procFClose
        
        exit
        
%include 'yasmlib.asm'

; void procReadLine()
; Read line to buffer 'line'
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 [readTheLastLine], byte 1
    .endOfLine:
    
    mov [line si], byte '$'
    mov [lineLength], si
    
    pop si
    pop cx
    pop bx
    pop ax
    ret

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

section .data

    readingFile:
        db 'input.dat', 00
        
    readingDescriptor:
        dw 0000
        
    writingFile:
        times 128 db 00
        
    writingDescriptor:
        dw 0000
        
    readTheLastLine:
        db 00
        
    line:
        db 64
        times 66 db '$'
        
    lineLength:
        dw 0000
    
    lineCount:
        dw 0000

GitHub link to macroses: yasmlib.asm/yasmmac.inc

Any help would be appreciated.

CodePudding user response:

I don't know how to print the decimal number in the file. I store this number in memory as hexadecimal. I need to convert that number to decimal and print it into the other file.

The solution to the problem is already in the yasmlib.asm file! It contains a code procUInt16ToStr that will convert the unsigned number in AX into an ASCIIZ string at the address in DX.
It does not return the length of the string, so you'll have to loop over the string and use procFPutChar to send the individual characters to the file. Alternatively and preferably loop over the string to establish the stringlength and output all at once with DOS function 40h (like you were doing already).

If you're interested in knowing how to convert from integer to string, then you could read my Q/A Displaying numbers with DOS.

.WritingToFile:
  mov  dx, Buffer
  mov  ax, [linecount]
  call procUInt16ToStr  ; produces an ASCIIZ string at DX
  mov  si, dx
.again:
  lodsb
  cmp  al, 0
  jne  .again
  sub  si, dx
  lea  cx, [si - 1]     ; -1 because we don't want to send the zero
  mov  bx, [writingDescriptor]
  mov  ah, 40h          ; DOS.WriteToFile
  int  21h              ; -> AX CF

Watch out with these

.untilEndOfFile:
    call procReadLine
    .firstColumn:
        mov al, [di]

This code is using DI without having initialized the register (mov di, line).

.skipALine:
    cmp [readTheLastLine], byte 0
    je .untilEndOfFile

Inspecting the readTheLastLine variable comes too late! You need this directly following the return from the procReadLine procedure:

.untilEndOfFile:
    call procReadLine
    cmp  byte [readTheLastLine], 0
    je   .WritingToFile
    mov  di, line
.firstColumn:
    mov al, [di]
    ...
    jmp  .untilEndOfFile
.WritingToFile:

You don't need that wasteful procAddNumber procedure to increment the linecount variable.
Simply replace call procAddNumber by inc word [linecount].

CodePudding user response:

While the other answer dealt with your question about writing the textual representation of the number, this answer focusses on a fundamental misunderstanding about what the task is asking.

TASK: count how many lines in the first two sections contain the letters 'B' and 'C'

Your current program is counting the lines that neither contain a 'B' nor a 'C'. The opposite from what was asked. Next will give you the count of lines that either contain a 'B' or a 'C'.

.untilEndOfFile:
    call procReadLine
    cmp  byte [readTheLastLine], 0
    je   .WritingToFile

    ...

    jne  .secondColumn
    jmp  .untilEndOfFile
.skipALine:
    inc  word [linecount]
    jmp  .untilEndOfFile
.WritingToFile:

Note that the above is still not literally "contain the letters 'B' and 'C'", it's more like "contain the letters 'B' or 'C'". But don't worry, a distinction that is very important in programming might not always be considered that important in day to day speech/writing.

  • Related