assembly 如何将十进制数逐字符写入文件8086 YASM

voj3qocg  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(119)

我有一个任务,我会尽量解释清楚。有一个文件与[0; 1000]行。每行包含6列。
前两列包含带有[1; 20]个字符。字符可以是 * 字母、数字和空格 *。
3-5列包含范围为 [-100; 100]。第6列包含范围真实的 [-9.99; 9.99],小数点后只有两位数。
每一节I用分号'隔开;'.

文件示例:

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:**计算前两部分中有多少行包含字母'B'和'C'。并在另一个文件中打印该整数。

我几乎完成了所有的任务,除了一件事。我不知道如何打印文件中的十进制数。我在内存中以 * 十六进制 * 存储该数。我需要将该数转换为 * 十进制 * 并将其打印到另一个文件中。
我在挣扎,因为可能只有1行,但也可能有1000行。所以我需要打印1个字符(如果行的数量在[0; 9]),但它可能是900个好的行,所以然后程序必须打印3个字符。

我的代码

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链接到宏:yasmlib.asm/yasmmac.inc

任何帮助都将不胜感激。

23c0lvtd

23c0lvtd1#

我不知道如何打印文件中的十进制数。我将该数作为十六进制存储在内存中。我需要将该数转换为十进制数,然后将其打印到另一个文件中。
该问题的解决方案已在yasmlib.asm文件中!它包含一个代码 * procUInt 16 ToStr *,该代码将AX中的无符号数字转换为DX中地址处的ASCIIZ字符串。
它不返回字符串的长度,所以你必须循环遍历字符串,并使用 procFPutChar 将单个字符发送到文件中。或者,最好循环遍历字符串,建立stringlength,并使用DOS函数40 h一次性输出(就像你已经做的那样)。
如果你有兴趣知道 * 如何 * 将整数转换为字符串,那么你可以阅读我的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

小心这些

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

此代码使用DI,但未初始化寄存器(mov di, line)。

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

检查 readTheLastLine 变量来得太晚了!您需要在 procReadLine 过程返回后直接检查 * readTheLastLine* 变量:

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

您不需要使用浪费的 procAddNumber 过程来递增 linecount 变量。
只需将call procAddNumber替换为inc word [linecount]即可。

au9on6nz

au9on6nz2#

而另一个答案是关于你的问题,即写数字的文本表示,这个答案集中在一个基本的误解,即任务是问什么。

TASK:计算前两个部分中包含字母“B”和“C”的行数

您目前的程式正在计算既不包含'B'也不包含'C'的行数。这与所要求的正好相反。Next会给予您计算包含'B'或'C'的行数。

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

    ...

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

请注意,上面的内容并不是字面上的“包含字母'B''C'”,它更像是“包含字母'B''C'”。但是不用担心,在编程中非常重要的区别可能并不总是被认为在日常的演讲/写作中那么重要。

相关问题