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.