Remove Element in Array [ASSEMBLY] [duplicate] - arrays

I have input like this:
This is, ,,, *&% a ::; demo + String. +Need to**#!/// format:::::!!! this.`
Output Required:
ThisisademoStringNeedtoformatthis
I have to do this without using str_trim.
Edit: I am writing an encryption program. I have to remove all punctuation from the string and turn all lower case letters to uppercase before I encrypt it.
I added the code. I need to remove the spaces, or any punctuation before I turn it to upper case. So far I haven't found anything in my book that could help with this except str_trim which we aren't allowed to use.
INCLUDE Irvine32.inc
.data
source byte "This is the source string",0
.code
main proc
mov esi,0 ; index register
mov ecx,SIZEOF source ; loop counter
L1:
mov al,source[esi] ; get a character from source
and source[esi], 11011111b ; convert lower case to upper case
inc esi ; move to next character
loop L1 ; repeat for entire string
mov edx, OFFSET source
call WriteString
exit
main endp
end main

Your are already trying to change from lowercase to uppercase, so, I will give you a hand to remove the punctuation. Next code uses my suggestion : moving the uppercase letters to an auxiliary string ignoring the punctuation characters. I used EMU8086 compiler :
.stack 100h
.data
source db "STRING, WITH. PUNCTUATION : AND * SPACES!$"
aux db " "
.code
mov ax, #data
mov ds, ax
;REMOVE EVERYTHING BUT UPPERCASE LETTERS.
mov si, offset source ; POINT TO STRING.
mov di, offset aux ; POINT TO AUXILIARY.
L1:
mov al, [ si ] ; get character from source
;CHECK IF END STRING ($).
cmp al, '$'
je finale
;CHECK IF CHAR IS UPPERCASE LETTER.
cmp al, 65
jb is_not_a_letter ; CHAR IS LOWER THAN 'A'.
cmp al, 90
ja is_not_a_letter ; CHAR IS HIGHER THAN 'Z'.
;COPY LETTER TO AUX STRING.
mov [ di ], al
inc di ; POSITION FOR NEXT CHARACTER.
is_not_a_letter:
inc si ; move to next character
jmp L1
finale:
mov [ di ], al ; '$', NECESSARY TO PRINT.
;PRINT STRING.
mov dx, OFFSET aux
mov ah, 9
int 21h
;END PROGRAM.
mov ax, 4c00h
int 21h
I ended the strings with '$' because I print the string with int 21h.
As you can see, I'm not using CX nor the LOOP instruction. What I do is to repeat until '$' is found. You can do the same until 0 is found.

This is my code after removing all the punctuation and turning it to uppercase.
INCLUDE Irvine32.inc
.data
source byte "STriNG, ## WITH.[][][ lalalala PUncTuATION : AND * SpaceS!", 0
target byte SIZEOF source DUP(0), 0
.code
main PROC
pushad
mov edx, offset source
call WriteString
call CrlF
mov edx, 0
mov esi, offset source
mov edi, offset target
L1:
mov al, [ esi ] ; get character from source
cmp al, 0
je final
cmp al, 65
jb not_letter ; if char is lower than 'A' jump to not letter
cmp al, 122
ja not_letter ; if char is greater than 'z' jump to not letter
cmp al, 90
ja Label1 ; jump if above 'Z'
jmp next ; false
Label1:
cmp al, 97
jl Label2 ; jmp if less than 'a'
jmp next ; false
Label2: ; if both are true than is greater than 'Z' but less than 'a'
jmp not_letter ; jump to not letter
next:
mov [ edi ], al
inc di ; position to next character.
not_letter:
inc si ; move to next character
jmp L1
final:
mov [ edi ], al
mov edx, OFFSET target
mov ah, 9
call WriteString
call CrlF
mov esi,0 ; index register
mov ecx,SIZEOF source ; loop counter
L2:
mov al, target[esi] ; get a character from source
and target[esi], 11011111b ; convert lower case to upper case
inc esi ; move to next character
loop L2 ; repeat for entire string
mov edx, OFFSET target
call WriteString
call CrlF
popad
exit
main endp
end main

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 a triangle with incrementing digits instead of asterisks

I'm experimenting with my program by trying to build different kinds of pyramids and converting the values into different values. I managed to build one with asterisk sign and now I'm trying to find a way on how to change it into running numbers like "0123456789" and the next line is "012345678" and so on. Is there a way to do that without fully/less changes of my code?
.MODEL SMALL
.STACK 100H
.DATA
STAR DB ?
BLANK DB ?
.CODE
MAIN PROC
MOV AX,#DATA
MOV DS,AX
MOV CX,10
MOV BH,10
MOV BL,0
MOV STAR,BH
MOV BLANK,BL
L1:
CMP BLANK,0
JE L2
MOV AH,2
MOV DL,32
INT 21H
DEC BLANK
JMP L1
L2:
MOV AH,2
MOV DL,'*'
INT 21H
DEC STAR
CMP STAR,0
JNE L2
MOV AH,2
MOV DL,0AH
INT 21H
MOV DL,0DH
INT 21H
DEC BH
MOV STAR,BH
INC BL
MOV BLANK,BL
LOOP L1
EXIT:
MOV AH,4CH
INT 21H
MAIN ENDP
END MAIN
I'm trying to find a way on how to change it into running numbers like "0123456789" and the next line is "012345678" and so on. Is there a way to do that without fully/less changes of my code?
While the other answer provides an alternative solution, my solution keeps most of your program intact as per request, only adding the digit sequence:
L2:
mov dl, '0' <--- Setup 1st digit
L3: <--- Extra label
MOV AH,2
INT 21H
inc dl <--- To next digit
DEC STAR
CMP STAR,0 ; Tip: you can remove this instruction
JNE L3 <--- To extra label
Expected output (similar to your asterisks):
0123456789
012345678
01234567
0123456
012345
01234
0123
012
01
0
Consider a simplier algorithm which uses DOS function Int 21h/AH=09h (which displays $-terminated strings). You may shorten the string by overwriting characters at its end with '$' in each loop cycle:
.MODEL SMALL
.STACK 100H
.DATA
EOL DB 13,10,'$' ; End of line string.
TXT DB '0123456789$' ; The initial string.
.CODE
MAIN PROC
MOV AX,#DATA
MOV DS,AX ; Initialize DS to .DATA segment.
MOV AH,9 ; Use DOS function WRITE STRING TO STANDARD OUTPUT.
MOV BX,10 ; Initialize the number of iteration (address index).
L1: MOV DX,OFFSET EOL
INT 21H ; Write EOL first.
MOV [TXT+BX],'$' ; Terminate TXT at index BX.
MOV DX,OFFSET TXT
INT 21H ; Write TXT.
DEC BX ; Let BX index the previous character.
JNZ L1 ; Loop while BX > 0.
EXIT:MOV AH,4CH
INT 21H
MAIN ENDP
END MAIN
Result should be this:
0123456789
012345678
01234567
0123456
012345
01234
0123
012
01
0

Loop input assembly x86

The program needs to iterate trough the input that a user enters and replace every underscore character ("_") that it finds with "#".
The program does it, but just one time, then every underscore character that is found, stays the same.
.MODEL SMALL
.STACK
.DATA
string_input DB "Enter a string: $"
string_output DB "Your string is: $"
bufferLong db 250
inputLong db 0
buffer db 250, 0, 250 dup ("$"), "$"
.CODE
start:
mov ax, #data
mov ds, ax
mov dx, offset string_input
mov ah, 09h
int 21h
call inputString
;mov cl, al
mov dl, 0Ah
mov ah, 02h
int 21h
mov dl, 0Dh
mov ah, 02h
int 21h
mov dx, offset string_output
mov ah, 09h
int 21h
;mov al, cl
call outputString
mov ax, 4C00h
int 21h
inputString proc
mov dx, offset bufferLong
mov ah, 0Ah
int 21h
ret
inputString endp
outputString proc
mov dx, offset buffer
mov ah, 09h
mov si,0
mov cx, 0
mov bl, "_"
loop:
cmp bl, buffer[si]
je replace
inc cx
inc si
jne loop
replace:
mov buffer[si], "#"
int 21h
ret
outputString endp
end start
bufferLong db 250
inputLong db 0
buffer db 250, 0, 250 dup ("$"), "$"
This looks like you don't truly know what the required input structure for this DOS.BufferedInput function 0Ah should look like. Read more about it at How buffered input works.
This is the correct definition:
bufferLong db 250
inputLong db 0
buffer db 250 dup (0)
Upon the first replacement, you immediately print the result, where in fact you should continu the loop. Better change the conditional jump to the opposite like this (from je to jne):
xor si, si
loop:
mov al, buffer[si]
cmp al, 13
je print ; Exit the loop upon finding 13
cmp al, "_"
jne skip ; While skipping you stay in the loop
replace:
mov buffer[si], "#"
skip:
inc si
jmp loop ; Unconditionally to the top where a possible exit can get detected
print:
mov buffer[si], "$"
mov dx, offset buffer
mov ah, 09h
int 21h
ret
What your 'loop' was missing is a clear way to exit. The string that you process ends with a carriage return (13). Use that to stop iterating. This could happen from the start if the user did not type in characters and just used enter.
Next you need to provide the correct string termination so DOS can print the result. Preloading the input buffer with $ characters serves no purpose. Just store one $ character either replacing the byte 13 or else right behind the byte 13.

Can't find the reason for a build error on Assembly language program which converts a string Array into an integer array

I am creating a program which reads a list of integers seperated by a single space via console and printing the sum of all the integers. The main problem is extracting the integers from the string array into a signed integer array.
Some examples of input are "-20 30 5" (each integer is seperated by a single space) or " [space]-20 30 5 [space]" (there may be spaces between the beginning and the end of the list, but the numbers are still seperated by a single space)
Also, after printing the sum, the program returns to reading another input unless only the enter key is typed.
After writing the code and pressing the Debug button, I am getting these two following build errors:
A2005 symbol redefinition: InBuffer
A2111 conflicting parameter definition
I've checked the error messages and apparently both of them are related to the PROTO and PROC directives. But there seems to be no problems regarding the parameter definition.
Here is my code.
INCLUDE Irvine32.inc
ArrayGet PROTO, ; convert string array into int array
inBuffer: PTR BYTE,
inBufferN: DWORD,
intArray: PTR SDWORD
.data
BUF_SIZE EQU 256
inBuffer BYTE BUF_SIZE DUP(?) ; input buffer
inBufferN DWORD ? ; length of input
intArray SDWORD BUF_SIZE/2 DUP(?) ; integer array for storing converted string
intArrayN DWORD ? ; number of integers
prompt BYTE "Enter numbers(<ent> to exit) : ", 0
bye BYTE "Bye!", 0
.code
main PROC
L1:
mov esi, 0
mov edx, OFFSET prompt
call WriteString
mov edx, OFFSET inBuffer
mov ecx, BUF_SIZE
call ReadString
cmp inBuffer[0], 0ah
je L3 ; only typing <ent> ends the program
mov inBufferN, eax
mov ecx, inBufferN
SpaceCheck: ; calls procedure when it finds a number
cmp inBuffer[esi], 20h
jne L2
inc esi
loop SpaceCheck
jmp L1
L2:
INVOKE ArrayGet, ADDR inBuffer, inBufferN, ADDR intArray ; put inBuffer offset on edx, inBufferN on ecx
mov intArrayN, eax
mov ecx, intArrayN
mov eax, 0
mov esi, OFFSET intArray
Ladd: ; adding the integer array
add eax, [esi]
inc esi
loop Ladd
call WriteInt
call CRLF
jmp L1
L3:
mov edx, OFFSET bye
call WriteString
exit
main ENDP
; procedure definition
ArrayGet PROC USES edx ecx,
inBuffer : PTR BYTE,
inBufferN: DWORD,
intArray: PTR SDWORD
LOCAL ArrayNum: DWORD
mov ArrayNum, 0
mov ecx, inBufferN
sub ecx, esi ; ecx(loop count) from first char to the end
LOOP1:
lea edx, inBuffer
add edx, esi ; edx points the offset of first char
mov edi, esi ; save location of first char
LOOP2: ; check spaces between integers
cmp inBuffer[esi], 20h
je getNum
inc esi
loop LOOP2
jmp getNum ; jump to getNum if array ends with a number
getNum: ; converting char into int
push ecx
inc esi
cmp inBuffer[esi], 20h ; two spaces in a row is considered as no more numbers afterwards
je EndBuffer
dec esi
mov ecx, esi
sub ecx, edi ; length of single number in char
call ParseInteger32
mov edi, ArrayNum
mov intArray[edi], eax
inc ArrayNum
inc esi
pop ecx
loop LOOP1
jmp EndBuffer ; end procedure when loop is over
EndBuffer:
mov eax, ArrayNum
inc eax
ret
ArrayGet ENDP
END main
In case you have questions about my intentions in the code or about the form of the input, feel free to leave it at the comment section

Change only one letter in string

I have 2 string and one letter.
selectedWords BYTE "BICYCLE"
guessWords BYTE "-------"
inputLetter BYTE 'C'
Base on this answers, I write code who compere if selectedWords have letter C and If this is the case he need to change string guessWords:
guessWords "--C-C--"
But from some strange reason I get all other possibilities, just not correct one. Some suggestions on how to solve this problem.
First, forget the so called string instructions (scas, comps, movs). Second, you need a fixed pointer (dispkacement) with an index, e.g [esi+ebx]. Have you considered that WriteString needs a null-terminated string?
INCLUDE Irvine32.inc
.DATA
selectedWords BYTE "BICYCLE"
guessWords BYTE SIZEOF selectedWords DUP ('-'), 0 ; With null-termination for WriteString
inputLetter BYTE 'C'
.CODE
main PROC
mov esi, offset selectedWords ; Source
mov edi, offset guessWords ; Destination
mov ecx, LENGTHOF selectedWords ; Number of bytes to check
mov al, inputLetter ; Search for that character
xor ebx, ebx ; Index EBX = 0
ride_hard_loop:
cmp [esi+ebx], al ; Compare memory/register
jne #F ; Skip next line if no match
mov [edi+ebx], al ; Hang 'em lower
##:
inc ebx ; Increment pointer
dec ecx ; Decrement counter
jne ride_hard_loop ; Jump if ECX != 0
mov edx, edi
call WriteString ; Irvine32: Write a null-terminated string pointed to by EDX
exit ; Irvine32: ExitProcess
main ENDP
END main

Resources