Printing inputted string in assembly language - string

I wanna print what the user inputted first. However, it displays the converted uppercase already before the result.
Here's my code:
org 100h
BEGIN:
LEA DX, DASH1
MOV AH, 9
INT 21H
LEA DX,LOWERCASE
MOV AH,09H
INT 21H
LEA SI,STR1
MOV AH,01H
READ:
INT 21H
MOV BL,AL
CMP AL,0DH
JE DISPLAY
XOR AL,20H
MOV [SI],AL
INC SI
JMP READ
DISPLAY:
MOV AL,"$"
MOV [SI],AL
LEA DX,UPPERCASE
MOV AH,09H
INT 21H
LEA DX, STR1
MOV AH, 09H
INT 21H
MOV DL, BH ; space
MOV AH, 02H
INT 21H
LEA DX, UPPERCASE_
MOV AH, 9
INT 21H
LEA DX,STR1
MOV AH,09H
INT 21H
LEA DX, DASH2
MOV AH, 9
INT 21H
MOV AH,4CH
INT 21H
ret
LOWERCASE DB 0DH,0AH,0AH, " Input a 5-letter string: $"
UPPERCASE DB 0DH,0AH, " The uppercase equivalent of $"
UPPERCASE_ DB "is $"
DASH1 DB 0AH,0DH, " ================================================================= $"
DASH2 DB 0AH,0AH,0DH, " ================================================================= $"
STR1 DB 255 DUP(?)
Output:
Input a 5-letter string: asdfg
The uppercase equivalent of ASDFG is ASDFG
^ i want this part to print as `asdfg`
making it The uppercase equivalent of asdfg is ASDFG
P.S. also, how do I make the string limited to 5 only? Its because the string a user can input can exceed more than 5. Any tips?
==============================================================================

You are displaying strings UPPERCASE, STR1, UPPERCASE_,STR1, respectively, no wonder that STR1 remains the same. You need to reserve one more string STRorig where you should store the obtained character before its case is changed.
You can use DI to address STRorig and then perform STOSB for saving original AL to ES:DI and incrementing DI.
When you want to limit the size of input string, compare SI with STR1 + 5 and if it's above, act as if AL was equal to 0DH.

Related

Need help combining two strings TASM

I need help in combining two programs I have and I can't seem to get it working for me. Don't get the desired output.
So here's my problem statement:
Combine Two separate strings in a third string and display it, Where the first String is as it is and the second string is reversed.
Example:
Input:
String 1: 'Hello'
String 2: '.dlroW '
Output:
'Hello World.'
end of Example.
Now there are two ways we can go about this.
First: Use string functions.(Preferred)
Now I am fairly new to learning Assembly Language so I would like to do it using string functions so I can learn something New.
Second: Without using string functions.
Another Approach is if someone can help combining two programs, One for the concatenation of the string and the other for reversal, Note that I have written the two individual programs and they run well without any hiccups, I just can't seem to do it together. How I am going about with this is before concatenating the string I am trying to reverse it, then proceeding with the addition of the second string. But I can't seem to get it working. I've tried to the best of my knowledge.
//Concatenation Code
.model tiny
.data
msg1 db 10,13,"Enter the string 1: $"
cat db 30 DUP('$')
msg2 db 10,13,"Enter the string 2: $"
msg3 db 10,13,"Concatenated string is: $"
.code
mov ax,#data
mov ds,ax
lea dx,msg1
mov ah,09h
int 21h
lea si,cat
up: mov ah,01h
int 21h
mov [si],al
inc si
cmp al,0dh
jnz up
lea dx,msg2
mov ah,09h
int 21h
dec si
up1: mov ah,01h
int 21h
mov [si],al
inc si
cmp al,0dh
jnz up1
lea dx,msg3
mov ah,09h
int 21h
lea dx,cat
mov ah,09h
int 21h
mov ah,4ch
int 21h
end`
Here's Part 2
//Reversal Code
.model tiny
.data
msg1 db 10,13,"enter the string: $"
string db 40 DUP('$')
rev db 40 DUP('$')
msg2 db 10,13,"reverse string is: $"
.code
mov ax,#data
mov ds,ax
lea dx,msg1
mov ah,09h
int 21h
mov ah,0ah
lea dx,string
int 21h
lea si,string
lea di,rev
mov cl,[si+1]
mov ch,00h
add di,cx
inc si
inc si
up: mov al,[si]
mov [di],al
inc si
dec di
loop up
inc di
mov ah,09h
lea dx,msg2
int 21h
mov ah,09h
lea dx,[di]
int 21h
mov ah,4ch
int 21h
end
And Here is the code I came Up with by combining those two.
//That's the code I tried Combining
.model tiny
.data
.model tiny
.data
msg1 db 10,13,"Enter string1: $"
cat db 30 DUP('$')
msg2 db 10,13,"Enter string2: $"
msg3 db 10,13,"Concatenated string is: $"
.code
mov ax, #data
mov ds,ax
lea dx,msg1
mov ah,09h
int 21h
lea si,cat
up: mov ah,01h
int 21h
mov [si],al
inc si
cmp al,0dh
jnz up
lea dx, msg2
mov ah,09h
int 21h
dec si
up2:mov al,[si]
mov [di],al
inc si
dec di
loop up2
inc di
up1:mov ah,01h
int 21h
mov [si],al
inc si
cmp al,0dh
jnz up1
lea dx,msg3
mov ah,09h
int 21h
lea dx,cat
mov ah,09h
int 21h
mov ah,4ch
int 21h
end
My Output
As you can see clearly I have failed at doing either task correctly. So can someone tell me where I am going wrong? Or teach me how to do this using the string Functions?
The up2 loop that tries to do string reversal comes too soon!. You've placed it where the 2nd string (the one that needs reversal) isn't even inputted yet.
If you would have written comments in your program, then you would probably have noticed this yourself.
This up2 loop uses the LOOP instruction that depends on the CX register but your program does not assign any suitable value to CX.
And also your working reversal program is using 2 buffers. Why then do you expect the combo to work from a single buffer?
Define the cat buffer so it can hold both strings.
Define the str buffer so it can hold the second string.
lea dx, msg1
mov ah, 09h ; DOS.PrintString
int 21h
lea di, cat
up: ; Input f i r s t string
mov ah, 01h ; DOS.GetCharacter
int 21h ; -> AL
mov [di], al
inc di
cmp al, 13
jne up
dec di ; Throw out the 13
; This marks the start of the reversed string, VERY IMPORTANT
; So don't change DI while inputting the 2nd string
lea dx, msg2
mov ah, 09h ; DOS.PrintString
int 21h
lea si, str
mov dx, si
up1: ; Input s e c o n d string
mov ah, 01h ; DOS.GetCharacter
int 21h ; -> AL
mov [si], al
inc si
cmp al, 13
jne up1
dec si ; Throw out the 13
cmp si, dx
je done ; Second string was empty. CAN HAPPEN!
up2: ; Reversed copying of s e c o n d string
dec si
mov al, [si]
mov [di], al
inc di
cmp si, dx
ja up2
done:
mov ax, 0A0Dh ; Add a proper carriage return and linefeed to the result
mov [di], ax
mov al, '$' ; Terminate the result with a dollar sign
mov [di+2], al
lea dx, msg3
mov ah, 09h ; DOS.PrintString
int 21h
lea dx, cat
mov ah, 09h ; DOS.PrintString
int 21h
First: Use string functions.(Preferred)
Both in the up loop and in the up2 loop, do you find next pair of instructions:
mov [di], al
inc di
Provided
the direction flag DF is clear so that DI can increment
the ES segment register points to #data
you can replace these 2 instructions by a single STOSB instruction.
This is what needs to go on top of your program:
.code
mov ax, #data
mov ds, ax
mov es, ax
cld
If we allowed ourselves to write a silly sequence of multiple std (set direction flag) and cld (clear direction flag) instructions, we could also replace mov al, [si] with lodsb. Care must be taken to keep a valid SI pointer (*).
dec si ; (*)
up2: ; Reversed copying of s e c o n d string
std
lodsb ; Due to STD, SI will decrement
cld
stosb ; Due to CLD, DI will increment
cmp si, dx
jae up2 ; (*)
done:
mov ax, 0A0Dh ; Add a proper carriage return and linefeed to the result
stosw
mov al, '$' ; Terminate the result with a dollar sign
stosb
In code that sets the direction flag (using std) it is best to end with a cld instruction so the direction flag is in the state we most expect!

Reversing an input string in Assembly

I have this assembly code that reverses a string that I input. It only accepts maximum 20 characters. My problem is that when I hit enter to see the output there is an extra character at the end of the reversed string.
Please help me understand why that does occur and how I can remove that in the output.
We're required to only use function 09H int 21h to display the string and function 0Ah int 21h to input the string. We're using TASM.
Your help would be very much appreciated. Thank you.
Here is my code:
.model small
.stack 100h
.data
MSG DB "Input String(max 20 chars): ", 10, 13, "$"
Sentence1 DB 21,?,21 dup("$")
str2 dw 21 dup("$")
.code
start:
mov ax, #data
mov ds, ax
;Getting the string input
mov ah,09h
lea dx, MSG
int 21h
lea si,Sentence1
mov ah,0ah
mov dx,si
int 21h
;Reverse String
mov cl,Sentence1
add cl,1
add si,2
loop1:
inc si
cmp byte ptr[si],"$"
jne loop1
dec si
lea di,str2
loop2:
mov al,byte ptr[si]
mov byte ptr[di],al
dec si
inc di
loop loop2
;Printing the reverse string
mov ah,09h
lea dx,str2
int 21h
mov ah, 4ch
int 21h
end start
str2 dw 21 dup("$")
Normally this would be using the db directive.
mov cl,Sentence1
add cl,1
The reversal loop uses CX as its loop counter, but you don't set it correctly!
The 2nd byte of the "Sentence1" input structure, contains the value that you want in the CX register. You don't need to search for any terminating character. Moreover if you did, you'd rather have to look for ASCII code 13 (carriage return) instead of '$'.
mov cl, [si + 1] ;Number of characters in the string
mov ch, 0 ;Make it a word because LOOP depends on CX (not just CL)
Setting up SI then becomes:
add si, 2 ;To the start of the string
add si, cx ;To the position after the string
dec si ;To the last character of the string
but shorter:
add si, cx
inc si
If ever the user didn't input any text, you will want to by-pass the reversal entirely! That's what the jcxz is for in next code:
lea si, Sentence1
mov ah, 0Ah
mov dx, si
int 21h
;Reverse String
mov cl, [si + 1]
mov ch, 0
add si, cx
inc si
lea di, str2
jcxz EmptyString ;By-pass the reversal entirely!
loop2:
mov al, byte ptr[si]
mov byte ptr[di], al
dec si
inc di
loop loop2
EmptyString:
;Printing the reverse string (could be empty)
mov ah, 09h
lea dx, str2
int 21h

Assembly Language: Completing the program to get the midstring

.model small
.stack
.data
msg1 db "Enter string max of 9 characters: $"
msg2 db 13,10, "Enter a number: $"
msg3 db 13,10, "Midstring: $"
strNine db "$"
num db 0,"$"
mid db "$"
varName label byte
maxL db 10
actL db 0
actCont db 10 dup("?")
.code
mov ax,#data
mov ds,ax
;-------------------- Input String ---------------------
mov ah,9
lea dx,msg1
int 21h
mov ah,0ah
int 21h
mov strNine,al
mov bh,strNine
;-------------------- Number ---------------------
mov ah,9
lea dx,msg2
int 21h
mov ah,1
int 21h
mov num,al
mov bl,num
;-------------------- Midstring ---------------------
mov ah,9
lea dx,msg3
int 21h
mov ah,4ch
int 21h
END
I need to find the midstring and I'm stuck since I'm new to Assembly Language.
Expected behaviour:
Enter max of 9 String: helloword
Enter a number: 3
Midstring: lloword
The leading space, the h and e shall be deleted because of the number input by the user.
The only part the I've gotten is to get the input from the user which is the string and number which i have saved in the BX memory which is used for indexing
I just need some tips/guides from you guys to finish the program.
mov ah,9
lea dx,msg1
int 21h
mov ah,0ah
int 21h
How can this input work at all? At the moment that you call the DOS input function your DX register is still set for the msg1 when it should be set to point to the varName input structure.
mov ah,0ah
int 21h
mov strNine,al
mov bh,strNine
What do you expect the AL register to hold at this point? This DOS function doesn't store a useful value there!

Getting string input and displaying input with DOS interrupts MASM

In MASM, I created a buffer variable to hold the user string input from keyboard. I am stuck on how to hold the string input into that buffer variable. I don't have any libraries linked like the irvine ones and want to do this with DOS interrupts. So far I have something along the lines of
.model small
.stack 100h
.data
buff db 25 dup(0), 10, 13
lbuff EQU ($ - buff) ; bytes in a string
.code
main:
mov ax, #data
mov ds, ax
mov ah, 0Ah ; doesn't work
mov buff, ah ; doesn't seem right
int 21h
mov ax, 4000h ; display to screen
mov bx, 1
mov cx, lbuff
mov dx, OFFSET buff
int 21h
mov ah, 4ch
int 21h
end main
I assume using 0Ah is correct as it is for reading array of input of buffered characters.
I made some changes to your code. First, the "buff" variable needs the three level format (max number of characters allowed, another byte for the number of characteres entered, and the buffer itself) because that's what service 0AH requires. To use service 0AH I added "offset buff" (as Wolfgang said). Here it is:
.model small
.stack 100h
.data
buff db 26 ;MAX NUMBER OF CHARACTERS ALLOWED (25).
db ? ;NUMBER OF CHARACTERS ENTERED BY USER.
db 26 dup(0) ;CHARACTERS ENTERED BY USER.
.code
main:
mov ax, #data
mov ds, ax
;CAPTURE STRING FROM KEYBOARD.
mov ah, 0Ah ;SERVICE TO CAPTURE STRING FROM KEYBOARD.
mov dx, offset buff
int 21h
;CHANGE CHR(13) BY '$'.
mov si, offset buff + 1 ;NUMBER OF CHARACTERS ENTERED.
mov cl, [ si ] ;MOVE LENGTH TO CL.
mov ch, 0 ;CLEAR CH TO USE CX.
inc cx ;TO REACH CHR(13).
add si, cx ;NOW SI POINTS TO CHR(13).
mov al, '$'
mov [ si ], al ;REPLACE CHR(13) BY '$'.
;DISPLAY STRING.
mov ah, 9 ;SERVICE TO DISPLAY STRING.
mov dx, offset buff + 2 ;MUST END WITH '$'.
int 21h
mov ah, 4ch
int 21h
end main
When 0AH captures the string from keyboard, it ends with ENTER (character 13), that's why, if you want to capture 25 characters, you must specify 26.
To know how many characters the user entered (length), access the second byte (offset buff + 1). The ENTER is not included, so, if user types 8 characters and ENTER, this second byte will contain the number 8, not 9.
The entered characters start at offset buff + 2, and they end when character 13 appears. We use this to add the length to buff+2 + 1 to replace chr(13) by '$'. Now we can display the string.
This is my code,maybe can help you.
;Input String Copy output
dataarea segment
BUFFER db 81
db ?
STRING DB 81 DUP(?)
STR1 DB 10,13,'$'
dataarea ends
extra segment
MESS1 DB 'After Copy',10,13,'$'
MESS2 DB 81 DUP(?)
extra ends
code segment
main proc far
assume cs:code,ds:dataarea,es:extra
start:
push ds
sub ax,ax
push ax
mov ax,dataarea
mov ds,ax
mov ax,extra
mov es,ax
lea dx,BUFFER
mov ah,0ah
int 21h
lea si,STRING
lea di,MESS2
mov ch,0
mov cl,BUFFER+1
cld
rep movsb
mov al,'$'
mov es:[di],al
lea dx,STR1 ;to next line
mov ah,09h
int 21h
push es
pop ds
lea dx,MESS1 ;output:after copy
mov ah,09h
int 21h
lea dx,MESS2
mov ah,09h
int 21h
ret
main endp
code ends
end start
And the result is:
c:\demo.exe
Hello World!
After Copy
Hello World!
You may follow this code :
; Problem : input array from user
.MODEL SMALL
.STACK
.DATA
ARR DB 10 DUB (?)
.CODE
MAIN PROC
MOV AX, #DATA
MOV DS, AX
XOR BX, BX
MOV CX, 5
FOR:
MOV AH, 1
INT 21H
MOV ARR[BX], AL
INC BX
LOOP FOR
XOR BX, BX
MOV CX, 5
PRINT:
MOV AX, ARR[BX] ;point to the current index
MOV AH, 2 ;output
MOV DL, AX
INT 21H
INC BX ;move pointer to the next element
LOOP PRINT ;loop until done
MAIN ENDP
;try this one, it takes a 10 character string input from user and displays it after in this manner, "Hello *10character string input"
.MODEL TINY
.CODE
.286
ORG 100h
START:
MOV DX, OFFSET BUFFER
MOV AH, 0ah
INT 21h
JMP PRINT
BUFFER DB 10,?, 10 dup(' ')
PRINT:
MOV AH, 02
MOV DL, 0ah
INT 21h
MOV AH, 9
MOV DX, OFFSET M1
INT 21h
XOR BX, BX
MOV BL, BUFFER[1]
MOV BUFFER [BX+2], '$'
MOV DX, OFFSET BUFFER +2
MOV AH, 9
INT 21h
M1: db 'Hello $'
END START
END

String assembly

The task is to search a string and find if inputted char is in the string MES3 or not.Here is my code , but it doesn`t search all letters in the string just the first .How can i make the cycle to work and search through all symbols in the string
masm
model small
.DATA
MSG1 DB 10,13,'CHARACTER FOUND :) $'
MSG2 DB 10,13,'CHARACTER NOT FOUND :($'
MSG3 DB 10,13,'there is no hope of doing this bla : $'
MSG4 DB 10,13,'ENTER THE CHARACTER TO BE SEARCHED : $'
NEW DB 10,13,'$'
NEW1 DB 10,13,'$'
NEW2 DB 10,13,'$'
.CODE
ASSUME CS:#CODE,DS:#DATA
START:
MOV AX,#DATA
MOV DS,AX
LEA di,[MSG3]
DOWN:
LEA dx,NEW
MOV AH,09H
INT 21H
LEA DX,MSG4
MOV AH,09H
INT 21H
MOV AH,01H
INT 21H
MOV DI,0
UP1:
CMP AL,[MSG3+di]
JE DOWN3
INC DI
LOOP UP1
LEA DX,MSG2
MOV AH,09H
INT 21H
JMP FINISH
DOWN3:
LEA DX,MSG1
MOV AH,09H
INT 21H
FINISH:
INT 3
mov AX, 4c00h
int 21h
END START
The LOOP instruction (that you use in LOOP UP1) decrements CX and jumps to the target label if CX != 0. So you need to set CX to the maximum number of characters to compare before the UP1 label.
Or you could replace LOOP UP1 with CMP BYTE PTR [MSG3-1+di],'$' / JNE UP1 since the string is '$'-terminated.

Resources