Сборка х86 программы.Подсчет чисел во входе - PullRequest
0 голосов
/ 16 октября 2018

Здравствуйте, я только изучаю ассемблер, поэтому пока не очень разбираюсь во многих вещах.

Мне нужно написать программу, в которой пользователь вводит какую-то строку из различных буквенных чисел и т. Д. И программа должнапосчитайте, сколько чисел на входе, и распечатайте счетчик.

Вот мой код:

    .model small
.stack 100h

.data

    buffer      db 100, ?, 100 dup (0)
    count       db 0

.code

start:

    mov ax, @data
    mov ds, ax

    mov dx, offset buffer
    mov ah, 0Ah
    int 21h

    mov ah, buffer
    xor si, si
    xor cx, cx
  .loop:

  .notdigit:

    mov dl, buffer[si]
    inc Si
    cmp dl, 0
    jz .end

    cmp dl, '0'
    jb .notdigit
    cmp dl, '9'
    ja .notdigit
    inc count
    jmp .loop

  .end:

; count contains the digit count


    mov dl, count
    mov ah, 2h
    int 21h

Я не получаю ошибок, но программа не работает, когда я запускаюэто.

Что здесь не так?И как мне это изменить?

Ответы [ 3 ]

0 голосов
/ 19 октября 2018

Смысл этого кода в том, чтобы продемонстрировать один из нескольких методов, которые можно использовать для возврата десятичного целого числа, представляющего количество цифр в строке, так как эта часть отсутствует в OP.Обычно после этого используется какой-то алгоритм преобразования, но я подумал, что было бы интересно посмотреть, как это можно сделать при разборе строки.

Поскольку многие примеры приложений DOS по сути являются не более чем плоской памятьюВ моделях я обойдусь без лишних вещей, таких как секции (.data, .const, .text) и использую RET , чтобы вернуться в командную строку, так как нас не очень заботит код возврата.Редко я резервирую место, как в COM файле, и все, что происходит, - это раздувает приложение.

Собран с использованием NASM name.asm -oname.com версия2.11.08

Протестировано с использованием DOSBOX 0.74

      WRITE_STR equ  9
       READ_STR equ 0xc0a       ; Buffered input with initial flush
          DOS   equ 33

    org 100H            ; DOS 6.22 COM file 
; ----------------------------------------------------------------------------

Begin:

    ; Every program should have some sort of prompting so operator has an idea
    ; of what is expected.

    mov dx, Prompt
    mov ah, WRITE_STR
    int DOS

    ; Not absolutely required, but AH = 0CH & AL = 0AH accepts buffered input
    ; but assures there aren't any straggling characters as buffer pointed to by
    ; DX is flushed first.

    mov dx, Users_Entry
    mov ax, READ_STR
    int DOS 

    ; Setup pointer to string, count of characters entered and initial count
    ; of digit characters in string

    mov     si, dx          ; Point to input buffer
    inc     si          ; Bounce over maximum characters
    xor     ax, ax
    push    ax
    lodsb               ; Read # of characters entered
    mov     cx, ax          ; Move to counter register for loop

    ; Of the four possible outcomes, each message must be preceded with
    ; double return & tab.

    mov dx, PreAmb
    mov ah, WRITE_STR
    int DOS

    ; The reason AX is being used because a packed BCD value is going to be
    ; created on the fly, but for this to work DAA must be used and it only
    ; works on the accumulator.

    pop ax          ; Restore initial digits count
    mov dx, Err00       ; By default, assume nothing was entered.
    jcxz    Finished        ; Branch in buffer is empty

    .NextChr:
    mov bl, [si]        ; Read first or next character
    inc si          ; Bump pointer
    cmp bl, '0'
    jb  .notNum
    cmp bl, '9'
    ja  .notNum
    add al, 1
    daa             ; Bump counter and decimal adjust
    .notNum:
    loop    .NextChr

    mov dx, Msg01       ; Assume a single digit character.
    cmp al, 1
    jz  Finished
    mov dx, Msg00
    or  al, al
    jz  Finished        ; No digit characters found

    ; Now we are going to replace the word "No" with the BCD value in AX
    cld
    mov di, dx
    push    ax
    mov dx, di          ; Needed to ultimately display string

    ; There is a good change the value is < 10, so initially we are going
    ; to convert to space.

    shr ax, 4           ; Shift tens into low nibble
    or  al, ' '
    cmp al, ' '
    jz  $ + 4           ; I
    or  al, 10000b      ; Convert ot digit 1 - 9
    stosb               ; Write to destination string
    pop ax
    and ax, 1111b       ; Mask out high nibble (tens)
    or  al, '0'
    stosb               ; Write units digit.

    ; Now the appropriate final message can be displayed appending modified
    ; PreAmb to it.

Finished:
    call    Show            ; Display desired result string

    mov dx, PreAmb + 1      ; Do one less line-feed
    mov di, dx
    mov byte [di+2], '$'        ; Don't want to do TAB
Show:
    mov ah, WRITE_STR
    int DOS
    ret             ; Return to DOS or maybe DEBUG

; NOTE: alignment is for convenience sake so things can be identified a little
;       more readily using hex dumps in DEBUG.

    align   16
; ----------------------------------------------------------------------------

    Prompt: db  27, '[2J', 10   ; VT100 emulation clears screen and sets
                    ; cursor to 0:0
        db  ' Please enter alphanumeric string (max 48 chars)'
        db  10, 10, '    --> $'

     PreAmb:    db  10, 10, 9, '$'
     Err00: db  '--> FAILED <-- NULL string$'

     Msg00: db  'No digit characters were found$'
     Msg01: db  'Only a single digit character found$'

    align   8

    Users_Entry:    db  49      ; NOTE: change prompting text too.
0 голосов
/ 20 октября 2018

Input

buffer      db 100, ?, 100 dup (0)

Это правильное определение для входного буфера, который будет использоваться функциями DOS 0Ah, , но позже, когда вы захотите пройтифактическая входная строка, вам нужно пропустить первые 2 байта, поскольку они не являются частью фактического введенного текста!
Вы можете изменить xor si, si на mov si, 2.

cmp dl, 0
jz .end

Ввод, который доставляет вам DOS, завершается возвратом каретки (ASCII 13), поэтому проверка на ноль бесполезна.


В приведенном ниже коде используется AL вместо DLпотому что полученный код сборки будет немного короче.
Альтернативные решения существуют, но это наиболее близко к тому, что вы получили:

    mov     si, 2
.loop:
    mov     al, buffer[si]
    inc     si
    cmp     al, 13
    je      .end
    cmp     al, '0'
    jb      .loop      ;notdigit
    cmp     al, '9'
    ja      .loop      ;notdigit
    inc     count
    jmp     .loop
.end:

Вывод

mov dl, count
mov ah, 2h
int 21h

Эта функция DOS ожидает символ в DL.Ваша переменная count - это просто число, скорее всего, очень маленькое число!
Вы можете легко преобразовать маленькие числа от 0 до 9 в соответствующие им символы, добавив 48.

    mov     dl, count
    add     dl, '0'    ;ASCII code for '0' is 48
    mov     ah, 02h
    int     21h
0 голосов
/ 16 октября 2018

Программист несет ответственность за явное возвращение потока управления операционной системе (в вашем случае это DOS).Это делается с помощью следующего системного вызова:

mov ah, 4Ch
mov al, 0
int 21h

Вы должны поместить эти три строки в конец исходного файла сборки.

Также верно, что count содержитколичество цифр в пользовательском вводе, но в дополнительном формате 2, что не то, что вам нужно.Например, если в пользовательском вводе есть две цифры, count будет содержать значение 0000 0010b, которое, безусловно, не является кодом ASCII для числа два (это 32h или 0010 0000b).Если вы позволите вводить до 9 цифр в пользовательском вводе, дополнение 2 к ASCII-преобразованию выполняется очень легко:

add dl, '0'

Эта строка должна идти после mov dl, count и до mov ah, 2h.

...