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

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.

Related

Working with strings from file YASM (8086)

I have one task to do. I will try to explain it as clearly as possible.
When you run the program, it asks to input (reading file and writing file).
Reading file has lines in range [1; 999]. Every line has six columns. Every column is separated by semicolon (;).
First and second columns contains text symbols in range [1; 20].
Third - fifth columns contains integers [-100; 100].
Last column contains floating number [-9.99; 9.99]. With two symbols after point.
FILE EXAMPLE:
firstA;lB;lC;lD;lE;lF
A11;bas hello;0;0;5;1.15
B12; good day;-100;11;78;1.33
TASK:
Output: Only first and second columns, that doesn't contain numbers and symbols 'B', 'C'.
OUTPUT:
firstA, because only this column doesn't have 'B', 'C' and numbers.
Up to now I have written program, that just throws away numbers and symbols. I can't figure out the solution for the full TASK.
My program
%include 'yasmmac.inc'
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
org 100h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
section .text
startas:
macPutString 'Reading file name:', crlf, '$' ;Input for reading file
mov al, 128
mov dx, readingFile
call procGetStr
macNewLine
macPutString 'Writing file name: ', crlf, '$' ;Input for writing file
mov al, 128
mov dx, writingFile
call procGetStr
macNewLine
push readingFile
push writingFile
call function
exit
;Main Function
function:
push bp
mov bp, sp
sub sp, 4
push dx
push bx
push ax
mov dx, [bp+6]
call procFOpenForReading
jnc .secondFOpen
macPutString 'Error while opening file', crlf, '$'
jmp .end
.secondFOpen:
mov [bp-2], bx
mov dx, [bp+4]
call procFCreateOrTruncate
jnc .filter
macPutString 'Error while opening writing file', crlf, '$'
jmp .close
.filter:
mov [bp-4], bx
.whileNotTheEnd:
mov bx, [bp-2]
call procFGetChar
jnc .c1
macPutString 'Error while reading file', crlf, '$'
jmp .close
.c1:
cmp ax, 0 ; Checks if it is not the end of the file
jne .check
jmp .close ; If the end - close the file
.check:
mov al, cl
cmp al, ';' ; Checks if ';'
jne .c2
.c2:
cmp al, 30h ; Number checking
jge .c3
jmp .c4
.c3:
cmp al, 39h ; Number checking
jle .checkEnd
jmp .c4
.c4:
cmp al, 'B'
jne .c5
jmp .checkEnd
.c5:
cmp al, 'C'
jne .writing
jmp .checkEnd
.writing:
mov bx, [bp-4]
call procFPutChar
jnc .checkEnd
macPutString 'Error while writing file', crlf, '$'
jmp .close
.acheckEnd:
cmp ax, 0
jne .nextIteration
jmp .close
.nextIteration:
jmp .whileNotTheEnd
.close:
mov bx, [bp-4]
call procFClose
.closeReadingFile:
mov bx, [bp-2]
call procFClose
.end:
ret4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%include 'yasmlib.asm'
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
section .data
writingFile:
times 255 db 00
readingFile:
times 255 db 00
duomenys:
times 255 db 00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
section .bss
There's not much about "yasmmac.inc" to be found online, but I believe that my interpretation of what these procFGetChar and procFPutChar macros do will not be too far off...
The task will seem too complicated if you don't use a modular approach. You need to delegate the simpler subtasks to separate subroutines. Further it would make sense to abstract from where the data is coming from. Don't read a single character from the file and immediately have it classified. No, fetch a complete line from the file and process the requested fields from the memory copy. It will be so much easier and less prone to errors related to file access.
.whileNotTheEnd:
; Fetch one line from the file
call .fgets ; -> DI (AX BX CL)
test di, di
jz .close ; Normal EOF
; Process fields 1 and 2 from the memory copy
mov si, Buffer
call .field ; -> SI (AX BX)
call .field ; -> SI (AX BX)
jmp .whileNotTheEnd
.close:
mov bx, [bp-4]
call procFClose
mov bx, [bp-2]
call procFClose
The lines in the text file each end with a carriage return and linefeed pair (13,10). Finding the 10 therefore denotes the EOL.
Receiving AX=0 from DOS means the end of the file. If this happens when we have not yet characters in our buffer, it signals a normal EOF.
; ----------------------
; IN (bp) OUT (di) MOD (ax,bx,cl)
.fgets:
mov bx, [bp-2] ; Handle
xor di, di ; Counts characters
.more:
call procFGetChar ; -> AX CL CF
jc .err1
test ax, ax ; EOF ?
jz .eof
mov [Buffer + di], cl
inc di
cmp cl, 10
jne .more
.ret:
ret
.eof:
test di, di ; If DI==0 then Normal EOF
jz .ret
.err1:
macPutString 'Error while reading file', crlf, '$'
pop ax ; (*) Forget about `call fgets`
jmp .close
; ----------------------
The field subroutine does the magic of this program but even it will delegate to a further subroutine the classification of the character. This will enhance readability. As a rule of thumb, I try to keep each subroutine within the bounds of one screen (25 rows). Because this code will end with SI pointing after the current field, it will be real easy to continue with the 2nd field.
; ----------------------
; IN (si) OUT (si) MOD (ax,bx)
.field:
mov bx, si ; Remember the start of this field
.check:
lodsb
cmp al, ";"
je .write
call .test ; -> CF
jnc .check
.skip:
lodsb ; Skip remainder of this (bad) field
cmp al, ";"
jne .skip
ret
.write:
push si ; (1)
mov si, bx ; Send this field to file
lodsb
.w1:
call .fputc ; -> (AX BX)
lodsb
cmp al, ";"
jne .w1
pop si ; (1) SI points after the ";"
ret
; ----------------------
; IN (al) OUT (CF)
.test:
cmp al, "0"
jb .OK
cmp al, "9"
jbe .NOK
cmp al, "B"
je .NOK
cmp al, "C"
je .NOK
.OK:
clc
ret
.NOK:
stc
ret
; ----------------------
; IN (al,bp) OUT () MOD (ax,bx)
.fputc:
mov bx, [bp-4] ; Handle
call procFPutChar ; -> AX CF
jc .err2
test ax, ax
jz .err2
ret
.err2:
macPutString 'Error while writing file', crlf, '$'
pop ax ; (*) Forget about `call .fputc`
pop ax ; (*) Forget about `call .field`
jmp .close
; ----------------------
(*) The error exits in .fgets and .fputc need to balance the stack! They need "to forget" about the calls that were made before the jmp to .close can pass in all safety.

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.

Assembly Language code to count different characters but when any counter exceeds 9, it prints different symbols instead of that specific number [duplicate]

I've written a pretty simple code in asm x8086 and I'm facing an error. If anyone could help me with a brief explanation I would greatly appreciate it.
IDEAL
MODEL small
STACK 100h
DATASEG
; --------------------------
array db 10h, 04h, 04h, 04h, 04h, 04h, 04h, 04h, 04h, 04h
sum db 0
; --------------------------
CODESEG
start:
mov ax, #data
mov ds, ax
; --------------------------
xor cx, cx
mov al, 0
mov bx, offset array
StartLoop:
cmp cx, 10
jge EndLoop
add al, [bx]
add [sum],al
inc cx
inc bx
jmp StartLoop
EndLoop:
mov ah, 09h
int 21h
; --------------------------
exit:
mov ax, 4c00h
int 21h
END start
With the correction for the add to be replaced by mov as noted in your comment (Note that the line: add al, [bx] is actually mov al, [bx]) there's just the function call at the label EndLoop that's wrong!
You want to display the sum, and are using the DOS print function. This function 09h expects a pointer in DS:DX that you are not providing!
Even if you did, you would still have to convert the sum number in its text representation.
A quick solution here would be to content yourself and just display the result in the form of a single ASCII character. The hardcoded sum is 52 and so it is a displayable character:
EndLoop:
mov dl, [sum]
mov ah, 02h ;Single character output
int 21h
; --------------------------
exit:
mov ax, 4c00h
int 21h
One step further and we can display "52":
mov al,[sum]
mov ah,0
mov dl,10
div dl ---> AL=5 AH=2
add ax,3030h ---> AL="5" AH="2"
mov dh,ah ;preserve AH
mov dl,al
mov ah,02h
int 21h
mov dl,dh ;restore
int 21h
I don't see any error at all, the code will sum the array, display some random sh*t, and exit.
You probably want to display result of sum?
int 21h, ah=9 will display '$' terminated string from memory pointed to by dx.
So you need two things, convert the number in [sum] to string terminated by'$' at end, and then set dx to the converted string ahead of that int 21h.
You may try to extract number2string procedure from here: https://stackoverflow.com/a/29826819/4271923
I would personally change it to take the address of target buffer in si as another call argument (ie. just remove the mov si,offset str from the procedure body). Like this:
PROC number2string
; arguments:
; ax = unsigned number to convert
; si = pointer to string buffer (must have 6+ bytes)
; modifies: ax, bx, cx, dx, si
mov bx, 10 ; radix 10 (decimal number formatting)
xor cx, cx ; counter of extracted digits set to zero
number2string_divide_by_radix:
; calculate single digit
xor dx, dx ; dx = 0 (dx:ax = 32b number to divide)
div bx ; divide dx:ax by radix, remainder will be in dx
; store the remainder in stack
push dx
inc cx
; loop till number is zero
test ax, ax
jnz number2string_divide_by_radix
; now convert stored digits in stack into string
number2string_write_string:
pop dx
add dl, '0' ; convert 0-9 value into '0'-'9' ASCII character encoding
; store character at end of string
mov [si], dl
inc si
; loop till all digits are written
dec cx
jnz number2string_write_string
; store '$' terminator at end
mov BYTE PTR [si],'$'
ret
ENDP
Then to call this at your EndLoop you need to add into data segment numberStr DB 8 DUP (0) to have some memory buffer allocated for string and add into code:
; load sum as 16b unsigned value into ax
xor ax,ax ; ax = 0
mov al,[sum] ; ax = sum (16b zero extended)
; convert it to string
mov si,OFFSET numberStr
call number2string
; display the '$' terminated string
mov dx,OFFSET numberStr
mov ah,9
int 21h
; ... exit ...

Assembly programing bug

I'm new at programming assembly. Now I'm trying to write a program that converts number from decimal to binary. But I got stuck with one program while trying to input. After i output msg2 and get into loop, program doesn't turn off. I can input a lot of numbers and program doesn't turn off. I guess problem is in convertnumber: cmp si,cx (si is how many numbers I have to input, cx- how many numbers I have already written), but I am not sure about that. Where have I made a mistake and how could I correct it?
.MODEL small
.Stack 100h
.DATA
msg0 db 'how many numbers will include your input number(example. 123 is 3 numbers)? $'
msg1 db 'Now input number from 0 to 65535: $'
number db 255, ?, 256 dup ('$')
numberinAscii db 255, ?, 256 dup ('$')
enterbutton db 13,10,'$'
.CODE
start:
mov ax, #data
mov ds,ax
mov ah,09h
mov dx, offset msg0 ; first message output
int 21h
xor ah,ah ; function 00h of
int 16h ; int 16h gets a character (ASCII translation in AL)
int 3
mov bl,al
mov dl,al
mov ah,02h ; function 02h - display character
int 21h ; call DOS service
mov ah,09h
mov dx, offset enterbutton
int 21h
mov ah, 09h
mov dx, offset msg1 ; output second message
int 21h
jmp covertHowMany ; converting number that we entered
next:
xor si,si
mov si, ax ; number that we entered now is in si
xor cx,cx
mov cx,0 ;cx=0
enterfirstnumber: ;entering first number (example 123, first number is 1)
xor ah,ah
int 16h ; int 16h gets a one character
int 3
mov bl,al
mov dl,al
mov ah,02h ; function 02h - display character
int 21h ;
jmp convertnumber ; converting this number
input: ;converting number from ascii char to ascii integer
mov ax,bx
mov dx,10
mul dx ; ax:=ax*10
mov bx,ax ; number that I try to convert is in bx now
xor ah,ah
int 16h ; int 16h gets a character (ASCII translation in AL)
int 3
mov bl,al
mov dl,al
mov ah,02h ; function 02h - display character
int 21h
jmp convertnumber
convertHowMany:
sub al,30h ; convert from ascii character to ascii number
jmp next
convertnumber:
sub al,30h
add bx,ax
inc cx
cmp cx, si
jne input
jmp ending
ending:
mov ax,04C00h
int 21h
end start
I see at least two problems with your code:
The first is that when you reach convertHowMany you assume that AL still contains the character that the user typed in. That will not be the case, since both INT 21h/AH=02h and INT 21h/AH=09h modify AL. You'll have to save and restore the value of AL somehow (e.g. by pushing and popping AX).
The second problem is how you initialize SI before the loop. You're moving the value of AX into SI, which means both AL and AH. AH is not zero at that point, because you've just used INT 21h/AH=09h.
You could change the sequence xor si,si / mov si,ax into something like mov si,ax / and si,0FFh.

Increment an array in assembly

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.

Resources