[英]Assembly x86 program. Counting numbers in an input
您好,我只是在學習匯編,所以我還不太了解。
我必須編寫一個程序,用戶在其中輸入各種字母數字等的某種行。該程序應計算輸入中有多少個數字並打印出計數器。
這是我的代碼:
.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
我沒有收到任何錯誤,但是當我運行該程序時,它實際上並沒有運行。
怎么了 我應該如何改變呢?
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變量只是一個數字,很可能是一個非常小的數字!
您可以通過添加48將0到9的小數字輕松轉換為它們各自的字符。
mov dl, count
add dl, '0' ;ASCII code for '0' is 48
mov ah, 02h
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
之前。
該代碼的重點是演示幾種可用於返回表示字符串中數字字符數量的十進制整數的方法之一,因為這是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.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.