Assembly 汇编x86程序。计算输入中的数字

Assembly 汇编x86程序。计算输入中的数字,assembly,x86,counter,masm,x86-16,Assembly,X86,Counter,Masm,X86 16,你好,我只是在学习组装,所以我还不太懂很多东西 我必须编写一个程序,用户在其中输入一些不同字母、数字等的行,程序应该计算输入中有多少数字,并打印出计数器 这是我的密码: .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

你好,我只是在学习组装,所以我还不太懂很多东西

我必须编写一个程序,用户在其中输入一些不同字母、数字等的行,程序应该计算输入中有多少数字,并打印出计数器

这是我的密码:

    .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
我没有收到任何错误,但当我运行程序时,它实际上不工作


这里怎么了?我应该如何更改它?

程序员有责任明确地将控制流返回到操作系统(在您的情况下,它是DOS)。这是使用以下系统调用完成的:

mov ah, 4Ch
mov al, 0
int 21h
您应该将这三行放在程序集源文件的末尾

另外,
count
确实包含用户输入中的位数,但采用2的补码格式,这不是您所需要的。例如,如果用户输入中有两个数字,
count
将包含值
0000 0010b
,这肯定不是数字2的ASCII码(它是
32h
0010 0000b
)。如果允许在用户输入中最多显示9位数字,则可以非常轻松地完成2对ASCII的补码转换:

add dl, '0'

这一行应该在
mov dl,count
之后和
mov ah,2h
之前,程序员有责任明确地将控制流返回到操作系统(在您的情况下,它是DOS)。这是使用以下系统调用完成的:

mov ah, 4Ch
mov al, 0
int 21h
您应该将这三行放在程序集源文件的末尾

另外,
count
确实包含用户输入中的位数,但采用2的补码格式,这不是您所需要的。例如,如果用户输入中有两个数字,
count
将包含值
0000 0010b
,这肯定不是数字2的ASCII码(它是
32h
0010 0000b
)。如果允许在用户输入中最多显示9位数字,则可以非常轻松地完成2对ASCII的补码转换:

add dl, '0'

这一行应该在
mov dl,count
之后,在
mov ah,2h
之前。这段代码的目的是演示几种方法之一,这些方法可用于返回表示字符串中数字字符数的十进制整数,因为这是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.
WRITE_STR eq 9
读取字符串eq 0xc0a;带初始刷新的缓冲输入
DOS equ 33
org 100H;DOS 6.22 COM文件
; ----------------------------------------------------------------------------
开始:
; 每个程序都应该有某种提示,以便操作员有一个想法
; 这是预期的结果。
mov dx,提示
mov啊,写下
int DOS
; 并非绝对必需,但AH=0CH&AL=0AH接受缓冲输入
; 但要确保没有任何散乱的字符作为缓冲区指向
; 首先刷新DX。
mov dx,用户\输入
移动轴,读取
int DOS
; 设置指向字符串、输入字符数和初始计数的指针
; 字符串中的数字字符数
mov-si,dx;指向输入缓冲区
国际公司;跳转超过最大字符数
xor ax,ax
推斧
lodsb;读取输入的字符数
mov-cx,ax;移动到循环的计数器寄存器
; 在四种可能的结果中,每一条信息之前都必须加上
; 双重返回和标签。
前置放大器
mov啊,写下
int DOS
; 使用AX的原因是因为压缩BCD值将
; 动态创建,但要使其工作,必须使用DAA,并且仅
; 在蓄能器上工作。
爆裂斧;恢复初始数字计数
mov-dx,Err00;默认情况下,假定未输入任何内容。
jcxz完成;缓冲区中的分支为空
.NextChr:
mov-bl,[si];读第一个或下一个字符
国际公司;凹凸指针
cmp bl,“0”
约翰·诺纳姆
《基本法》第9条
是的,诺特纳姆
加上al,1
daa;碰撞计数器和十进制调整
诺纳姆先生:
loop.NextChr
mov-dx,Msg01;假定为一位数字字符。
cmp铝,1
jz完成
mov dx,Msg00
还是艾尔,艾尔
jz完成;找不到数字字符
; 现在我们将用AX中的BCD值替换单词“No”
cld
mov-di,dx
推斧
mov-dx,di;需要最终显示字符串
; 有一个很好的变化,值小于10,所以我们开始
; 转换为空间。
shr-ax,4;将十位移到低位
或者“艾尔”
化学机械抛光
jz$+4;我
或al,10000b;转换ot数字1-9
stosb;写入目标字符串
爆斧
和ax,1111b;屏蔽高字节(十位)
或“0”
stosb;写单位数字。
; 现在,可以显示相应的最终消息,并添加“已修改”
; 预告它。
完成:
电话秀;显示所需的结果字符串
mov dx,前置MB+1;少做一次换行
mov-di,dx
mov字节[di+2],“$”;不想做的事
展示:
mov啊,写下
int DOS
    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
    mov     dl, count
    add     dl, '0'    ;ASCII code for '0' is 48
    mov     ah, 02h
    int     21h