[英]Assembly x86 program. Counting numbers in an input
Hello I am just learning assembly so I don't really understand many things yet. 您好,我只是在学习汇编,所以我还不太了解。
I have to write a program where the user inputs some kind of line of various letters numbers etc. And the program should count how many numbers there are in the input and print the counter out. 我必须编写一个程序,用户在其中输入各种字母数字等的某种行。该程序应计算输入中有多少个数字并打印出计数器。
Here is my code: 这是我的代码:
.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
I get no errors but the program doesn't really work when I run it. 我没有收到任何错误,但是当我运行该程序时,它实际上并没有运行。
What is wrong here? 怎么了 And how should I change it?
我应该如何改变呢?
buffer db 100, ?, 100 dup (0)
This is the correct definition for an input buffer to be used by DOS's functions 0Ah, but later on when you want to traverse the actual input string, you need to skip the first 2 bytes since these are not part of the actual inputted text! 这是DOS函数0Ah使用的输入缓冲区的正确定义, 但是稍后要遍历实际输入字符串时,您需要跳过前2个字节,因为它们不是实际输入文本的一部分!
You can change xor si, si
into mov si, 2
. 您可以将
xor si, si
更改为mov si, 2
。
cmp dl, 0 jz .end
The input that DOS delivers you is terminated by a carriage return (ASCII 13) and so it is useless to test for a zero. DOS为您提供的输入以回车符(ASCII 13)终止,因此测试零是没有用的。
Below code uses AL
instead of DL
because the resulting assembly code will be a bit shorter. 下面的代码使用
AL
而不是DL
因为生成的汇编代码会短一些。
Alternative solutions exist but this one is closest to what you got: 存在替代解决方案,但这是最接近您的解决方案:
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
This DOS function expects a character in DL
. 该DOS函数要求
DL
有一个字符 。 Your count variable is just a number, most probably a very small number! 您的count变量只是一个数字,很可能是一个非常小的数字!
You can easily convert the small numbers from 0 to 9 into their respective characters by adding 48. 您可以通过添加48将0到9的小数字轻松转换为它们各自的字符。
mov dl, count
add dl, '0' ;ASCII code for '0' is 48
mov ah, 02h
int 21h
It is programmer's responsibility to explicitly return the flow of control to the operating system (in your case, it is DOS). 明确将控制流返回给操作系统(在您的情况下为DOS)是程序员的责任。 This is done using the following system call:
这是通过以下系统调用完成的:
mov ah, 4Ch
mov al, 0
int 21h
You should put these three lines at the end of your assembly source file. 您应该将这三行放在程序集源文件的末尾。
Also, it is true that count
contains the number of digits in the user input, but in 2's complement format, which is not what you need. 同样,
count
确实包含用户输入中的位数,但采用2的补码格式,这不是您所需要的。 For example, if there are two digits in the user input, count
will contain the value 0000 0010b
, which is certainly not ASCII code for the number two (it's 32h
or 0010 0000b
). 例如,如果用户输入中有两位数字,则
count
将包含值0000 0010b
,这肯定不是数字2的ASCII代码(它是32h
或0010 0000b
)。 If you allow up to 9 digits to appear in the user input, 2's complement to ASCII conversion is done very easily: 如果您最多允许9位数字出现在用户输入中,则2到ASCII转换的补码很容易完成:
add dl, '0'
This line should come after mov dl, count
and before mov ah, 2h
. 该行应在
mov dl, count
,在mov ah, 2h
之前。
The point to this code is to demonstrate one of a few methods that could be used to return a decimal integer representing the number of digit characters in a string, as that is the part that's missing from OP. 该代码的重点是演示几种可用于返回表示字符串中数字字符数量的十进制整数的方法之一,因为这是OP中缺少的部分。 Conventionally some sort of conversion algorithm is used after the fact, but I thought it might be interesting to see how it can be done while parsing the string.
事后,通常使用某种转换算法,但是我认为在解析字符串时如何完成转换可能会很有趣。
As many examples of DOS applications are essentially nothing more than flat memory models, I dispense with superfluous things like sections (.data, .const, .text) and use RET to return to the command prompt as we're not really concerned about a return code. 由于DOS应用程序的许多示例本质上仅是平面内存模型,因此我省去了诸如节(.data,.const,.text)之类的多余内容,并使用RET返回到命令提示符,因为我们并不真正关心返回码。 Rarely do I reserve space as in a COM file all that does is bloat the application.
我很少像COM文件中那样保留空间,这只会使应用程序肿。
Assembled using NASM name.asm -oname.com version 2.11.08
使用NASM name.asm -oname.com版本2.11.08组装
Tested using DOSBOX 0.74 使用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.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.