Reputation: 9
I need help with assembler(TASM), and I need to change one problem.
When filling a buffer of 200 elements, I need to make a transition to entering a word for deletion, but it does not work, help
.MODEL small
.STACK 100h
.DATA
msg1 DB "Enter string: $"
msg2 DB 0Ah, 0Dh, "Enter word to delete: $"
msg3 DB 0Ah, 0Dh, "Result: $"
str1ml DB 200 ; maximum buffer length
str1l DB 0 ; actual length of the entered string (DOS format)
str1 DB 200 dup('$') ; the characters of the string, filled with '$'
str2ml DB 200
str2l DB 0
str2 DB 200 dup('$')
.CODE
begin:
; Initialize DS and ES segments
mov ax, @data
mov ds, ax
mov es, ax
xor ax, ax
; Print message and input the main string
lea dx, msg1
call strout
lea dx, str1ml
call strin
; Check if the buffer is full
mov al, str1l
cmp al, str1ml
jb input_word ; if the buffer is not full, proceed to input the word
; If the buffer is full, add a terminating character
mov byte ptr [str1 + 200], '$' ; add a terminating character
input_word:
; Print message and input the substring (word to delete)
lea dx, msg2
call strout
lea dx, str2ml
call strin
; Check if the buffer is full
mov al, str2l
cmp al, str2ml
jb process_input ; if the buffer is not full, proceed to processing
; If the buffer is full, add a terminating character
mov byte ptr [str2 + 199], '$' ; add a terminating character
process_input:
; Prepare to search for the substring in the main string
xor cx, cx
mov cl, str1l ; load the length of the main string
sub cl, str2l ; calculate the number of possible positions for comparison
inc cl ; account for the last possible shift
cld ; clear the direction flag (forward traversal)
lea di, str2 ; DI points to the beginning of the substring
lea si, str1 ; SI points to the beginning of the main string
xor ax, ax
all_string:
; Search for a match of the substring at the current position in the main string
call sub_search
inc si ; shift one character to the right in the main string
loop all_string ; repeat the loop until CX is zero
; Move to a new line
call nextstr
; Print the final result
lea dx, msg3
call strout
lea dx, str1
call strout
_end:
mov ah, 4Ch ; DOS function to terminate the program
int 21h
; Procedure to move to a new line
nextstr proc
push dx
push ax
mov dl, 0Dh ; carriage return character
mov ah, 02h
int 21h
mov dl, 0Ah ; line feed character
mov ah, 02h
int 21h
pop ax
pop dx
ret
nextstr endp
; Procedure to input a string (DOS function 0Ah)
strin proc
mov ah, 0Ah
int 21h
ret
strin endp
; Procedure to output a string (DOS function 09h)
strout proc
mov ah, 09h
int 21h
ret
strout endp
; Procedure to search for a substring in a string
sub_search proc
push cx
push di
push si
mov bx, si ; save the starting address of the current comparison
mov cl, str2l ; set the counter to the length of the substring
repe cmpsb ; compare bytes while they are equal (SI and DI)
je _eq ; if all characters are equal, jump to deletion
jne _neq ; if a mismatch is found, jump to the end
_eq:
call delete ; call the procedure to delete the substring
inc al
_neq:
pop si
pop di
pop cx
ret
sub_search endp
; Procedure to delete a substring
delete proc
push bx
push di
push si
mov di, bx ; DI points to the beginning of the substring to delete
lea si, [bx + str2l] ; SI points to the character after the substring
mov cx, 200 ; maximum length of the string
sub cx, bx ; calculate the remaining length of the string
rep movsb ; copy the remaining part of the string
pop si
pop di
pop bx
ret
delete endp
end begin
What I Tried: I translated the comments in your assembly code from Russian to English to make it easier for English-speaking developers to understand the logic and purpose of each section of the code. I expected this to help clarify the functionality of the program, especially for those who might not be familiar with Russian.
Upvotes: 0
Views: 45
Reputation: 39506
Your program is not all that bad! Where it goes terribly wrong is in the delete proc. You move too many bytes down, you forget to $-terminate the resulting string, and you need to update the length variable for the first string so your all_string loop could successfully repeat the operation in case the substring appears multiple times.
lea si, [bx + str2l] ; SI points to the character after the substring
Since delete is reached from within sub_search, the successful repe cmpsb
will already have left the SI register pointing to the character after the substring. So this is a redundant instruction, as well as it is wrong in that you mistakenly use the address of str2l instead of the actual length!
mov cx, 200 ; maximum length of the string sub cx, bx ; calculate the remaining length of the string
You can't subtract an address (BX
) from a length (200
) just like that!
You can obtain the number of bytes to copy, from subtracting the address where the block starts (SI
) from the address where the block ends (str1 + [str1l]
).
What follows is an improved delete procedure, but you should not yet try to continue your all_string loop from it, because that would require additional improvements. At a minimum you should respond to this answer first ...
; IN (bx,si) OUT ()
push ax
push cx
push si
push di
mov di, bx ; Points to the beginning of substring to delete
mov cx, OFFSET str1
add cl, str1l ; CURRENT length of the string
adc ch, 0
sub cx, si ; -> CX is the length of remaining string
rep movsb ; copy the remaining part of the string
mov byte ptr [di], "$"
mov al, str2l
sub str1l, al ; New current length of the string
pop di
pop si
pop cx
pop ax
ret
Upvotes: 1