Как записать десятичное число одним символом в файл 8086 YASM

У меня есть задача, и я постараюсь объяснить ее понятно. Есть файл с [0; 1000] строк. Каждая строка содержит 6 столбцов.

Первые два столбца содержат строку с [1; 20] символов. Символами могут быть буквы, цифры и пробелы.

3-5 столбцы содержат целые числа в диапазоне [-100; 100]. 6-й столбец содержит действительные числа в диапазоне [-9,99; 9,99] только с двумя цифрами после запятой.

Каждый раздел я разделял точкой с запятой ';'.

ПРИМЕР ФАЙЛА:

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

ЗАДАНИЕ: подсчитайте, сколько строк в первых двух секциях содержит буквы «В» и «С». И напечатайте это целое число в другом файле.

Я сделал почти все задание, кроме одного. Я не знаю, как напечатать десятичное число в файле. Я храню это число в памяти как шестнадцатеричное. Мне нужно преобразовать это число в десятичное и распечатать его в другом файле.

Я борюсь, потому что может быть 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

Любая помощь будет оценена по достоинству.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я не знаю, как напечатать десятичное число в файле. Я храню это число в памяти как шестнадцатеричное. Мне нужно преобразовать это число в десятичное и распечатать его в другом файле.

Решение проблемы уже есть в файле yasmlib.asm! Он содержит код procUInt16ToStr, который преобразует беззнаковое число в AX в строку ASCIIZ по адресу в DX.
Он не возвращает длину строки, поэтому вам придется перебирать строку и использовать procFPutChar для отправки отдельных символов в файл. В качестве альтернативы и предпочтительно перебрать строку, чтобы установить длину строки и вывести все сразу с помощью функции DOS 40h (как вы уже делали).

Если вам интересно узнать, как преобразовать целое число в строку, вы можете прочитать мой вопрос/ответ Отображение чисел в 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:

.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].

Сейчас увидел один баг в этой программе. Каким-то образом максимальное значение, которое может получить lineCount, равно 255. Если хороших строк больше, чем 255, он перезапускает счетчик. У Вас есть мысли, почему так могло быть?

Kurbamit 17.11.2022 13:02

@Kurbamit Убедитесь, что переменная не определена как 8-битный байт. В исходной программе lineCount определяется как 16-битное слово, проверьте это. Обычно YASM следует за NASM, поэтому inc word [lineCount] должно быть хорошо, но вы также можете попробовать inc word ptr [lineCount] (как это делает MASM). И в крайнем случае попробуйте: mov ax, [lineCount]inc axmov [lineCount], ax.

Sep Roland 17.11.2022 13:48

@Kurbamit Является ли YASM чувствительным к регистру? В своем ответе я использовал linecount, но вы использовали lineCount. Будьте осторожны с копипастом!

Sep Roland 17.11.2022 13:50

В то время как другой ответ касался вашего вопроса о написании текстового представления числа, этот ответ фокусируется на фундаментальном непонимании того, что задает задача.

ЗАДАНИЕ: подсчитайте, сколько строк в первых двух секциях содержит буквы «В» и «С».

Ваша текущая программа подсчитывает строки, которые не содержат ни «B», ни «C». Противоположное тому, что спрашивали. Далее вы получите количество строк, содержащих либо «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»». Но не волнуйтесь, различие, которое очень важно в программировании, не всегда может считаться столь важным в повседневной устной/письменной речи.

Другие вопросы по теме