Increment an array in assembly - arrays

Coding an assembly program to be used as a dictionary. User gives in the word and the program checks whether that word is present or not. TASM, 16 bit. Program works perfect for the first two elements of the array but if I provide balls. , the 3rd element of the array, even though the next element of array is being chosen, (verified on emu8086, bx becomes 007ch,->refer to code<-), the repe cmpsb still finishes its check after a single try. works properly with the first two elements of the array. Here is my code
The program firsts checks the length and later the bits. Length check is ended when a period (.) is provided.
.model large
.data
arrayele db 00d ;to count if all elements of the array have been compared with
count db 00d ;length of input count
nl db 10d,13d,'$' ;newline
mne db "Not Equal$" ;message if not equal
me db "Equal$" ;message if equal
buf db 99,?,99 dup(?) ;buffer where the input will be saved
w0 db "hello$" ;word 0-5
w1 db "which$"
w2 db "balls$"
w3 db "table$"
w4 db "chair$"
w5 db "apples$"
words dw offset w0,offset w1 ;the array
dw offset w2,offset w3
dw offset w4,offset w5
.code
main proc
mov ax,#data
mov ds,ax
mov es,ax
;take user input
mov ah,0ah
mov dx,offset buf
int 21h
;print new line
mov ah,09h
mov dx,offset nl
int 21h
;load input to di
mov di,offset buf
add di,2
;//saving length to a variable
repeat:
mov al,[di]
inc count
cmp al,"."
je lenchck
inc di
jmp repeat
;//end saving
lenchck:
dec count ;as full stop (period) (.) is also included in the count
stringmatch1:
mov cx,0 ;reset register
mov arrayele,0 ;reset variable
stringmatch:
mov di,offset buf ;loading input to di
add di,2
;loading array element to si
mov bx,0
mov bl,byte ptr words
mov si,bx ;end loading array element to si
mov cl,count
repe cmpsb
je equal
inc arrayele
inc words ;next word in the array
mov bx,0 ;loading it
mov bl,byte ptr words
mov si,bx ;end loading
cmp arrayele,06d ;compare to check if all elements have been compared with
jg wrong
jmp stringmatch
wrong: ;load notequal message
mov dx,offset mne
jmp print
equal:
mov dx,offset me ;load equal message
print:
mov ah,09h ;print it
int 21h
mov ah,4ch ;exit the program
int 21h
main endp
end main

inc words ;next word in the array
No, sorry. You've incremented (what was) the offset of w0. You haven't moved to the next word in the array. You want something more like...
mov bx, offset words
top:
; get offset of a string
mov si, [bx]
; do your comparison
; start at beginning of input every time
mov di, offset buf + 2 ; don't need a separate operation
mov cl, count ; (are we sure ch is clear?)
repe cmpsb
je found
; no? get next offset in words array
add bx, 2
jmp top
In your loop where you look for the '.', what's going to happen if the pesky user doesn't enter a '.'? The second byte in your input buffer (buf + 1), after the interrupt returns, is the count actually entered. It includes the '.' (if there was one) and the Carriage Return (13 or 0Dh) that ended input. You may be able to use this information to rule out obviously incorrect input.

Related

How to write decimal number by one char to file 8086 YASM

I have a task and I will try to explain it clearly. There is a file with [0; 1000] lines. Each line contains 6 columns.
The first two columns contain string with [1; 20] characters. Characters could be letters, numbers, and whitespaces.
3-5 columns contain integers in the range [-100; 100].
6th column contain real numbers in range [-9.99; 9.99] with only two digits after decimal point.
Each section I separated by a semicolon ';'.
FILE EXAMPLE:
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
TASK: count how many lines in the first two sections contain the letters 'B' and 'C'. And print that integer number in the other file.
I did almost all the task, except one thing. I don't know how to print the decimal number in the file. I store this number in memory as hexadecimal. I need to convert that number to decimal and print it into the other file.
I am struggling because there could be 1 good line, but it also could be 1000 good lines. So I need to print 1 character (if the number of good lines is between [0; 9]), but it could be 900 good lines, so then the program has to print 3 characters.
MY CODE
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 link to macroses:
yasmlib.asm/yasmmac.inc
Any help would be appreciated.
I don't know how to print the decimal number in the file. I store this number in memory as hexadecimal. I need to convert that number to decimal and print it into the other file.
The solution to the problem is already in the yasmlib.asm file! It contains a code procUInt16ToStr that will convert the unsigned number in AX into an ASCIIZ string at the address in DX.
It does not return the length of the string, so you'll have to loop over the string and use procFPutChar to send the individual characters to the file. Alternatively and preferably loop over the string to establish the stringlength and output all at once with DOS function 40h (like you were doing already).
If you're interested in knowing how to convert from integer to string, then you could read my Q/A Displaying numbers with 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
Watch out with these
.untilEndOfFile:
call procReadLine
.firstColumn:
mov al, [di]
This code is using DI without having initialized the register (mov di, line).
.skipALine:
cmp [readTheLastLine], byte 0
je .untilEndOfFile
Inspecting the readTheLastLine variable comes too late! You need this directly following the return from the procReadLine procedure:
.untilEndOfFile:
call procReadLine
cmp byte [readTheLastLine], 0
je .WritingToFile
mov di, line
.firstColumn:
mov al, [di]
...
jmp .untilEndOfFile
.WritingToFile:
You don't need that wasteful procAddNumber procedure to increment the linecount variable.
Simply replace call procAddNumber by inc word [linecount].
While the other answer dealt with your question about writing the textual representation of the number, this answer focusses on a fundamental misunderstanding about what the task is asking.
TASK: count how many lines in the first two sections contain the letters 'B' and 'C'
Your current program is counting the lines that neither contain a 'B' nor a 'C'. The opposite from what was asked. Next will give you the count of lines that either contain a 'B' or a 'C'.
.untilEndOfFile:
call procReadLine
cmp byte [readTheLastLine], 0
je .WritingToFile
...
jne .secondColumn
jmp .untilEndOfFile
.skipALine:
inc word [linecount]
jmp .untilEndOfFile
.WritingToFile:
Note that the above is still not literally "contain the letters 'B' and 'C'", it's more like "contain the letters 'B' or 'C'". But don't worry, a distinction that is very important in programming might not always be considered that important in day to day speech/writing.

Printing an array but specific values highlighted {emu8086}

I want to print this array but also highlight specific characters from said array. This is my code:
include 'emu8086.inc'
.data
animales1 db 'BUBRPQYFODFZXIQ'
db 'MSVDJVQDTLOEATF'
db 'RCZPIFYGAZLPMFN'
db 'LVWKFFBKDXHFIUW'
db 'AOSEFQEMOOTGQUR'
db 'ELLWTGNJJKAJISJ'
db 'OVCOXLUEQTSDDSP'
db 'UEAEMTNYOLVYMGI'
db 'ORREPOMJZGYPHAI'
db 'IFTLCBJFVOYHLUB'
db 'WTOWZQFRAXQRLMR'
db 'KGNYIIHHHKFUKIJ'
db 'XMLSACGMVXEYSIT'
db 'TSOESQVSEQRFNPU'
db 'ODDQMDFWRGETDLY'
lenguajes2 db 'SLKFMBCULKVYUIM'
db 'TWCDQFYIVIKUXKB'
db 'GNIWEQBOSYEMDTJ'
db 'WDHFZZPUIEDERYQ'
db 'KMTGTKAKROMUSUV'
db 'BELBLLTUVJQHCRW'
db 'UPLUBYJKNUXORLF'
db 'SGMAOOEENBOGIWR'
db 'JVSTLPTEGPPNPJW'
db 'YINCASSEMBLYTTU'
db 'CHWTIOIWORDZDRV'
db 'BRZCNRAVRWAMUNU'
db 'KOMCOUKNGQEPQVS'
db 'XXRXJUJUBEXVGGA'
db 'MNKJQKZAACVCLDW'
char db 'a'
flag db 0
;Pez= 12,27,42
;Ave= 76,92,108
indx db 5,11,26,41,45 dup (' ')
.stack
.code
.start up
mov ax,0000h
mov bx,0000h
mov cx,0000h
mov dx,0000h
lea si, animales1
;call valueInArray
call printArrays
printArrays proc
mov bx,0000h
printArray:
mov dx,0000h
mov ah, 02h
mov dl,byte ptr[si+bx]
call valueinArray
cmp flag,1
jz printSpecial
int 21h
mov dl, 20h
int 21h
add bx, 1
add cl, 1
cmp cl,15
jz nextRow
jnz printArray
nextRow:
call nwLine
add ch,1
mov cl, 00h
cmp ch,15
jz finproc
jnz printArray
printSpecial:
lea di,char
mov byte ptr[di],dl
push ax
push bx
push cx
push dx
mov bp, offset char
mov dh,00h
mov al, 1
mov bh, 0
mov bl, 1111_0000b
mov cx, 1; calculate message size.
mov dx,0000h
mov ah, 13h
int 10h
mov dl, 20h
mov ah, 02h
int 21h
pop dx
pop cx
pop bx
pop ax
add bx, 1
add cl, 1
cmp cl,15
jz nextRow
jnz printArray
finproc:
ret
printArrays endp
nwLine PROC
MOV AH,02h
MOV DX,0Ah; imprime asscii 10 (nueva linea)
INT 21h
MOV DX,0Dh; imprime asscii 13 (retorno de carro)
INT 21h
RET
nwLine ENDP
valueInArray proc
mov flag, 0
mov di,0001h
iterar:
mov dh, indx[di]
cmp dh,20h
jz finvalueproc
cmp bl,dh
jz found
add di,1
jmp iterar
found:
mov flag,1
jmp finvalueproc:
finvalueproc:
ret
valueInArray endp
exit:
end
As you can see, the array 'indx' have the positions of the chars (The first number is the effective lenght of said array) that I want to highlight so I check if bx is in the position of said character to print it highlighted.
I have two problems at the moment, the first one is the highlighted characters are printing in a kinda random position and that messes up the rest, but I think I know why the position of the highlighted character that prints is wrong, because the interrupt that I use uses dh and dl as positioners but I do not know how to make it so it continues the flow of the rest. The second problem is that the character that prints is wrong, if you run it and check the variable char, it has an 'Z' but it prints a 'T'. I really need help. Pretty please. :(
indx db 5,11,26,41,45 dup (' ')
It could be that this line is not what you think it is!
Reading your explanation I think you really meant:
indx db 5, 11, 26, 41, 45, ' '
That is the length of the array which is 5, then followed by 4 offsets to the highlighted characters and 1 space character as a list terminator.
the first one is the highlighted characters are printing in a kinda random position and that messes up the rest, but I think I know why the position of the highlighted character that prints is wrong, because the interrupt that I use uses dh and dl as positioners but I do not know how to make it so it continues the flow of the rest.
Because your code to output the highlighted character uses mov dx,0000h, the BIOS function 13h places the character in the upperleft corner of the screen and the other, 'normal' characters will continue from there.
All you have to do is to ask BIOS where the cursor is at that moment using function 03h:
Replace
mov cx, 1; calculate message size.
mov dx,0000h
mov ah, 13h
int 10h
by
mov ah, 03h ; BIOS.GetCursorAndConfiguration
int 10h ; -> CX DX
mov cx, 1 ; message size
mov ah, 13h ; BIOS.WriteString
int 10h
Function 13h fetches from ES:BP. Did you setup the ES segment register?
The second problem is that the character that prints is wrong, if you run it and check the variable char, it has an 'Z' but it prints a 'T'.
Probably resolving the first problem will also resolve the second one.
There's a better, less convoluted way to output your highlighted character.
printSpecial:
push ax
push bx
push cx
mov cx, 1 ; ReplicationCount
mov bx, 00F0h ; DisplayPage 0, Attribute BlackOnBrightWhite (11110000b)
mov al, dl ; Character
mov ah, 09h ; BIOS.WriteCharacterAndAttribute
int 10h
mov ah, 0Eh ; BIOS.TeletypeCharacter
int 10h
pop cx
pop bx
pop ax
...
Function 09h will write your character with the colors that you need, and then function 0Eh will advance the cursor normally.

Printing an array of ascii values to the console as a string in assembly language 8086?

I'm new to assembly language coding and there's this program I'm trying to work out where I initialize an array of letters (in ascii), loop through it, and print it to the console window as a concatenated string. This is what I have so far:
.MODEL flat
.DATA
name1 DB 4Ah, 69h, 6Dh, 6Dh, 79h
.CODE
main PROC
mov ecx, 0
mov esi, offset name1
loop1:
mov dl, [esi]
mov ah, 2
inc esi
inc ecx
cmp ecx, 5
jne loop1
endlp:
mov eax, 4c00h
ret
main ENDP
END
I'm pretty lost. Some of what I have here is from others trying to help me, so sorry if it looks messy.
Everything about your question cries DOS. I would suggest you use the tiny model for these simple demonstration programs.
In the 16-bit environment it's natural to use 16-bit registers.
To execute DOS api services you place the requested parameters in selected registers and store the function number in the AH register. Then you issue an int 21h call.
A more efficient loop will count downward. Often you can avoid the need to compare before looping back because the flags have been set by the dec instruction.
If you place the data of your program below the code that exits to DOS, you avoid mistakenly executing it.
You can write an array of ASCII codes easier as a string. See the 3rd example.
ORG 256 ;This asks for the tiny model
mov cx, 5
mov si, offset array
again:
mov dl, [si]
mov ah, 02h
int 21h ;Display character
inc si
dec cx
jnz again
mov ax, 4C00h
int 21h ;Exit the program
array db 4Ah, 69h, 6Dh, 6Dh, 79h
An alternative program doesn't use the CX counter at all. It suffices to stop when the pointer SI is pointing beyond the last character.
ORG 256 ;This asks for the tiny model
mov si, offset array
again:
mov dl, [si]
mov ah, 02h
int 21h ;Display character
inc si
cmp si, offset array+5
jb again
mov ax, 4C00h
int 21h ;Exit the program
array db 4Ah, 69h, 6Dh, 6Dh, 79h
Another alternative program uses a zero delimiter on the array. To see if the delimiter was reached, you can write cmp dl, 0 je exit but a bit better is to write test dl, dl jz exit.
ORG 256 ;This asks for the tiny model
mov si, offset array
again:
mov dl, [si]
test dl, dl ;Test for zero delimiter
jz exit
mov ah, 02h
int 21h ;Display character
inc si
jmp again
exit:
mov ax, 4C00h
int 21h ;Exit the program
array db 'Jimmy', 0

Transform string into number (array size), input of that array and output it back. ASM

In this programm i struggle to convert string into number. I have spent around 10 hours with this code already (yeah, I'm a novice) and I have a strong feeling I'm so close to the point when it's gonna work... Please, prove me right or prove me wrong! =) I tried to add as many comments as possible in the most complicated (as for me) parts of the code so you can save your time in case you have a mood to help me out a little. I'll be glad to explaine code even more if neccessary. Sorry for my English and let's see the code.
model tiny
.code
org 0100h
start:
mov ax,cs
mov ds,ax
mov dx,offset text
mov ah,09h
int 21h
mov dx,offset x
mov ah,3fh
int 21h
mov dh,byte ptr[x+di] ; Loading first digit into elem.
sub dh,48
mov ah,2
CH2INT:mov elem,dh
_TEST: push di
OFFST1:mov cl,ah
dec cl
add di,di
loop OFFST1
mov dh,byte ptr[x+di] ; Loading next (x+di*2) digit into dh.
pop di ; Inc ah for the next iteration.
inc ah ; Here we see if next char is a digit or not,
cmp dh,"0" ; if it is (meaning that current digit isn't in the lowest position) -
jb INVAL ; multiplying current digit by 10 (our base),
cmp dh,"9" ; if not - jump to INVAL where we go on to the next digit (if there is any).
ja INVAL ; Push-pop ax just for convinience, I'm almost out of free-to-use registers.
push ax
mov al,elem
mov ten,10
imul ten
mov elem,al
pop ax
jmp _TEST
INVAL: mov al,elem ; Adding number we got to the sum which in the end (after jump to NEXT)
add sum,al ; will containe inputt size of array as a number, not a char.
push di
OFFST2:mov cl,ah
dec cl
add di,di
loop OFFST2
mov dh,byte ptr[x+di] ; Move next digit into dh (x+ah(wich was incremented earlier)+di).
pop di ; See if there is a next digit in x or previous one was the last one
cmp dh,"0" ; (I just hope that next value in memory after the inputt will not be a digit...
jb NEXT ; I understand that it's not nice and a luck game, but I do not yet come up with smthn better).
cmp dh,"9"
ja NEXT
push di ; Next few lines write next char into dh (but with index less by 1 than in previous
; few lines, where we checked is there any more digits in the inputt value left.
OFFST3:mov cl,ah
sub cl,2
add di,di
loop OFFST3
mov dh,byte ptr[x+di]
pop di
sub dh,48
jmp CH2INT ; Jump to next iteration to work with next digit in the inputt value
NEXT: mov dx,offset array
mov ah,3fh
int 21h
mov cl,sum
L: mov dh,byte ptr[array+di]
inc di
mov dl,dh
mov ah,02h
int 21h
loop L
mov ah,4Ch ; Service 4Ch - Terminate with Error Code
mov al,0 ; Error code
int 21h ; Interrupt 21h - DOS General Interrupts
ret
array db 256 dup (?) ; Array
x db ? ; Size of the array
ten db ?
text db "Enter number of elements in array: $"
elem db ? ; A single digit from the inputt value
sum db 0 ; Inputt value transformed into number
end start
Code written in TASM as a .com executable. It has some irrational things here and there but it's just for the clarity and due to the fact it's just a draft. Hugely appreciate your help! Thanks!
P.S. I'll be modifying the code over time in case you'll give me some advise.

Assembly Language Array printing

I'm having a hard time with this homework assignment. I need to print my array showing that the numbers I pulled from ReadInt are in it. I'm not sure how to do that.
Here is my code so far.
.data
intarray DWORD ?
finish BYTE "Please enter a EVEN number less than 50. ", 0dh, 0ah, 0
finish2 BYTE "The entered array is: ", 0dh, 0ah, 0
finish3 BYTE "The sum of the first half of the array is: ", 0dh, 0ah, 0
finish4 BYTE "Please enter your numbers: ", 0dh, 0ah, 0
.code
main proc
mov edx, OFFSET finish
call WriteString
call crlf
call ReadInt
add intarray, eax
call crlf
mov edx, OFFSET finish4
call WriteString
call crlf
mov ecx,intarray
L1:
call ReadInt
mov intarray, eax
inc intarray
loop L1
mov edx, OFFSET finish2
call WriteString
call crlf
invoke ExitProcess,0
main endp
end main
I need to print my intarray to show that the number's entered by ReadInt are in it. I'm not sure how to do this.
Next code does what you need. The code was made with EMU8086 : it reads 10 numbers as strings (because data comes from keyboard), convert every string to number, insert them into the array, clears the screen, and displays the numbers in the array, converting every number to string (to display them). It's plenty of comments to help you understand (hope this helps you) :
.stack 100h
;------------------------------------------
.data
;------------------------------------------
array dw 10 dup(?)
msj db 13,10,'Enter a number: $'
str db 6 ;MAX NUMBER OF CHARACTERS ALLOWED (5).
db ? ;LENGTH (NUMBER OF CHARACTERS ENTERED BY USER).
db 6 dup (?) ;CHARACTERS ENTERED BY USER.
buf db 6 dup('$') ;WILL HOLD NUMBERS WITH 5 DIGITS OR LESS.
crlf db 13,10,'$'
count db ? ;JUST A COUNTER FOR LOOPS.
;------------------------------------------
.code
;INITIALIZE DATA SEGMENT.
mov ax, #data
mov ds, ax
;------------------------------------------
;CAPTURE 10 NUMBERS FROM USER.
mov di, offset array ;POINTER TO ARRAY.
mov count, 10 ;WE WILL CAPTURE 10 NUMBERS.
ten_numbers:
;DISPLAY MESSAGE.
mov ah, 9
mov dx, offset msj
int 21h
;CAPTURE NUMBER AS STRING.
mov ah, 0Ah
mov dx, offset str
int 21h
;CONVERT CAPTURED NUMBER FROM STRING TO NUMERIC.
mov si, offset str ;PARAMETER FOR STRING2NUMBER.
call string2number ;NUMBER RETURNS IN BX.
;INSERT NUMBER INTO ARRAY.
mov [ di ], bx ;NUMBER GOES IN CURRENT POSITION (DI).
add di, 2 ;ARRAY POSITION FOR THE NEXT NUMBER. MUST BE
;2 BECAUSE IT'S AN ARRAY OF DW (DW = TWO BYTES).
;REPEAT PROCESS.
dec count
jnz ten_numbers ;IF ( COUNT != 0 ) JUMP.
;------------------------------------------
;DISPLAY THE NUMBERS IN ARRAY.
call clear_screen
mov di, offset array
mov count, 10 ;ARRAY HAS 10 NUMBERS.
print_array:
;CONVERT NUMBER TO STRING TO DISPLAY IT.
call dollars ;FILLS BUF WITH DOLLARS (REQUIRED TO DISPLAY).
mov ax, [ di ] ;MOVE CURRENT NUMBER TO AX.
call number2string ;TAKES AX AS PARAMETER.
;STRING RETURNS IN VARIABLE BUF.
;DISPLAY STRING.
mov ah, 9
mov dx, offset buf
int 21h
;DISPLAY LINE BREAK.
mov ah, 9
mov dx, offset crlf
int 21h
;REPEAT PROCESS.
add di, 2 ;NEXT NUMBER IN ARRAY TO BE DISPLAYED. MUST BE
;2 BECAUSE IT'S AN ARRAY OF DW (DW = TWO BYTES).
dec count
jnz print_array ;IF ( COUNT != 0 ) JUMP.
;------------------------------------------
;WAIT FOR USER TO PRESS ANY KEY.
mov ah,7
int 21h
;------------------------------------------
;FINISH THE PROGRAM.
mov ax, 4c00h
int 21h
;==========================================
;NUMBER TO CONVERT MUST ENTER IN AX.
;ALGORITHM : EXTRACT DIGITS ONE BY ONE, STORE
;THEM IN STACK, THEN EXTRACT THEM IN REVERSE
;ORDER TO CONSTRUCT STRING (BUF).
proc number2string
mov bx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10.
mov cx, 0 ;COUNTER FOR EXTRACTED DIGITS.
cycle1:
mov dx, 0 ;NECESSARY TO DIVIDE BY BX.
div bx ;DX:AX / 10 = AX:QUOTIENT DX:REMAINDER.
push dx ;PRESERVE DIGIT EXTRACTED FOR LATER.
inc cx ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED.
cmp ax, 0 ;IF NUMBER IS
jne cycle1 ;NOT ZERO, LOOP.
;NOW RETRIEVE PUSHED DIGITS.
mov si, offset buf
cycle2:
pop dx
add dl, 48 ;CONVERT DIGIT TO CHARACTER.
mov [ si ], dl
inc si
loop cycle2
ret
endp
;------------------------------------------
;CONVERT STRING TO NUMBER IN BX.
;SI MUST ENTER POINTING TO THE STRING.
proc string2number
;MAKE SI TO POINT TO THE LEAST SIGNIFICANT DIGIT.
inc si ;POINTS TO THE NUMBER OF CHARACTERS ENTERED.
mov cl, [ si ] ;NUMBER OF CHARACTERS ENTERED.
mov ch, 0 ;CLEAR CH, NOW CX==CL.
add si, cx ;NOW SI POINTS TO LEAST SIGNIFICANT DIGIT.
;CONVERT STRING.
mov bx, 0
mov bp, 1 ;MULTIPLE OF 10 TO MULTIPLY EVERY DIGIT.
repeat:
;CONVERT CHARACTER.
mov al, [ si ] ;CHARACTER TO PROCESS.
sub al, 48 ;CONVERT ASCII CHARACTER TO DIGIT.
mov ah, 0 ;CLEAR AH, NOW AX==AL.
mul bp ;AX*BP = DX:AX.
add bx,ax ;ADD RESULT TO BX.
;INCREASE MULTIPLE OF 10 (1, 10, 100...).
mov ax, bp
mov bp, 10
mul bp ;AX*10 = DX:AX.
mov bp, ax ;NEW MULTIPLE OF 10.
;CHECK IF WE HAVE FINISHED.
dec si ;NEXT DIGIT TO PROCESS.
loop repeat ;COUNTER CX-1, IF NOT ZERO, REPEAT.
ret
endp
;------------------------------------------
;FILLS VARIABLE BUF WITH '$'.
;USED BEFORE CONVERT NUMBERS TO STRING, BECAUSE
;THESE STRINGS WILL BE DISPLAYED.
proc dollars
mov si, offset buf
mov cx, 6
six_dollars:
mov al, '$'
mov [ si ], al
inc si
loop six_dollars
ret
endp
;------------------------------------------
proc clear_screen
mov ah,0
mov al,3
int 10H
ret
endp
Maybe it's important to explain a little the variable str, notice the three level format, it's using 3 DBs because ah=0Ah (capture string) requires it : the first DB must indicate the max number of characters allowed, a second DB is necessary to store the length, and the third DB are the characters themselves. The string ends with ENTER (character 13), that's why the first DB is 6 (if user enters 5 characters, the sixth is ENTER).

Resources