I am not able to finish given task using DOS Debug:
Every input string symbol, that has even number of bits has to be changed to 0. And then string has to be reversed and printed to the screen.
a200
db 50
a260
db 'Enter string' 0d 0a '$'
a100
mov ah, 09
mov dx, 260
int 21
mov ah, 0a
mov dx, 200
int 21
mov ah, 02
mov dl, 0d
int 21
mov ah, 02
mov dl, 0a
int 21
xor cx, cx
mov bx, 201
mov cl, [bx]
int bx
mov dl, [bx]
inc bx
mov dl, [bx]
mov al, dl
mov ah, 0
clc
rcr al, 1
adc ah, 0
This is how far I was able to get. However, it is not finished. I am not sure if I am going to the right direction.
I have an idea to use perity flag to check if number of bits is even. However, I can't implement it.
int bx mov dl, [bx] inc bx mov dl, [bx] mov al, dl mov ah, 0 clc rcr al, 1 adc ah, 0
Up to reading the length of the user inputted string, your code looks fine, but then it starts to look like you've just thrown some random stuff together!
Your idea to use the parity flag is ok. When a byte has 0, 2, 4, 6, or 8 bits that are set (to 1), the PF will be set. When a byte has 1, 3, 5, or 7 bits that are set (to 1), the PF will be clear.
The x86 instruction set has 4 instructions that allow you to conditionally jump based on the state of the parity flag:
The jp
and jpe
instructions share the same opcode 7Ah.
jp
jump if parity (PF=1)jpe
jump if parity even (PF=1)The jnp
and jpo
instructions share the same opcode 7Bh.
jnp
jump if no parity (PF=0)jpo
jump if parity odd (PF=0)There are many instructions that modify the parity flag. The below code uses the cmp
instruction. In your program you want to zero in case of parity, which is equivalent to skip the zeroing in case of no parity. That's why the code uses the jnp
instruction.
...
011F mov cl, [bx]
0121 mov bx, 202 ; Where the string starts
0124 cmp byte ptr [bx], 0 ; Have the parity flag defined
0127 jnp 012C ; Skip in case of no parity
0129 mov byte ptr [bx], 0 ; Zero in case of parity
012C inc bx ; Go to next character
012D loop 0124 ; Until all characters have been processed
At the end of the above loop, the BX register points right behind the string. This is a good moment to apply the $-terminator that you will need in order to print your final result.
012F mov byte ptr [bx], "$"
The task of reversing the string requires maintaining two pointers that move towards each other while swapping bytes:
0132 dec bx ; Have BX point at the last byte in the string
0133 mov si, 202 ; Have SI point at the first byte in the string
0136 mov al, [bx] ; Read both bytes
0138 mov dl, [si]
013A mov [bx], dl ; Swap both bytes
013C mov [si], al
013E inc si ; Move towards the middle of the string
013F dec bx
0140 cmp si, bx ; Stop once the pointers cross
0142 jb 0136
EDIT 1
This edit deals with the OP's effort to implement the suggested solution.
This is the OP's code that reportedly runs into an infinite loop:
a200
db 50
a300
db 'Enter string' 0d 0a '$'
a100
mov ah, 09
mov dx, 300
int 21
mov ah, 0a
mov dx, 200
int 21
mov ah, 02
mov dl, 0d
int 21
mov ah, 02
mov dl, 0a
int 21
mov bx, 202
a200
cmp byte ptr [bx], 0
jnp 250
mov byte ptr [bx], 30
a250
inc bx
loop 200
mov byte ptr [bx], '$'
dec bx
mov si, 202
a400
mov al, [bx]
mov dl, [si]
mov [bx], dl
mov [si], al
inc si
dec bx
cmp si, bx
jb 400
mov dx, 202
mov ah, 09
int 21
mov ah, 4c
int 21
n lab1.com
r cx
800
w
q
The reasons why this fails are
loop
could now be running a very long time.a200
cmp byte ptr [bx], 0
you are overwriting the input buffer that you had setup with a200
db 50
. Keep data and code apart.a200
, a250
, and a400
you are leaving holes in the program. The CPU will try to execute the bytes that happen to exist in these holes, but since they are not instructions there's a high chance this will fail miserably. Look closely at the code I wrote in my answer. Those numbers (011F, 012F, 0132, ...) in the leftmost column are the addresses where the code belongs so the code forms one contiguous block.The whole code with corrections is:
a200
db 50 00
a300
db 'Enter string' 0D 0A '$'
a100
mov ah, 09 This is at address 0100
mov dx, 300
int 21
mov ah, 0A
mov dx, 200
int 21
mov ah, 02
mov dl, 0D
int 21
mov ah, 02
mov dl, 0A
int 21
xor cx, cx
mov bx, 201
mov cl, [bx]
mov bx, 202
cmp byte ptr [bx], 0 This is at address 0124
jnp 012C
mov byte ptr [bx], 30
inc bx This is at address 012C
loop 0124
mov byte ptr [bx], '$'
dec bx
mov si, 202
mov al, [bx] This is at address 0136
mov dl, [si]
mov [bx], dl
mov [si], al
inc si
dec bx
cmp si, bx
jb 0136
mov dx, 202
mov ah, 09
int 21
mov ah, 4C
int 21
n lab1.com
r cx
800
w
q
The w
command expects the file size in BX:CX. I assume you have checked BX=0 ?
EDIT 2
This edit deals with the OP's effort to refine the program so as to exempt the numerical digits from conversion.
This is the OP's code that reportedly crashes:
a200
db 50 00
a300
db 'Enter string' 0D 0A '$'
a100
mov ah, 09
mov dx, 300
int 21
mov ah, 0A
mov dx, 200
int 21
mov ah, 02
mov dl, 0D
int 21
mov ah, 02
mov dl, 0A
int 21
xor cx, cx
mov bx, 201
mov cl, [bx]
mov bx, 202
mov dl, byte ptr [bx] ; Put numerical representation of character into dl register
cmp dl, 39 ; Compare dl value with 39 (char '9')
jg 0132 ; If dl value is greater, it is not a digit, jump to parity flag's definition
cmp dl, 30 ; Compare dl value with 30 (char '0')
jge 013A ; If dl value is greater or equal then it is a digit, jump to the line where we increment bx
cmp byte ptr [bx], 0
jnp 013A
mov byte ptr [bx], 30
inc bx
loop 0124
mov byte ptr [bx], '$'
dec bx
mov si, 202
mov al, [bx]
mov dl, [si]
mov [bx], dl
mov [si], al
inc si
dec bx
cmp si, bx
jb 0144
mov dx, 202
mov ah, 09
int 21
mov ah, 4C
int 21
n lab1.com
r cx
800
w
q
The problem today is that the jump targets are off by 2.
You have added 5 lines of new code to your program. Together they take up 12 bytes, but the program seems to think it's 14 bytes.
0124: mov dl, byte ptr [bx] 2 bytes
0126: cmp dl, 39 3 bytes
0129: jg 0132 2 bytes
012B: cmp dl, 30 3 bytes
012E: jge 013A 2 bytes
0130: --------
12 bytes
The whole code with corrections is:
a200
db 50 00
a300
db 'Enter string' 0D 0A '$'
a100
mov ah, 09
mov dx, 300
int 21
mov ah, 0A
mov dx, 200
int 21
mov ah, 02
mov dl, 0D
int 21
mov ah, 02
mov dl, 0A
int 21
xor cx, cx
mov bx, 201
mov cl, [bx]
mov bx, 202
0124: mov dl, [bx]
0126: cmp dl, 39
0129: ja 0130 ERR jg 0132
012B: cmp dl, 30
012E: jae 0138 ERR jge 013A
0130: cmp byte ptr [bx], 0
0133: jnp 0138 ERR jnp 013A
0135: mov byte ptr [bx], 30
0138: inc bx
0139: loop 0124
013B: mov byte ptr [bx], '$'
013E: dec bx
013F: mov si, 202
0142: mov al, [bx]
0144: mov dl, [si]
0146: mov [bx], dl
0148: mov [si], al
014A: inc si
014B: dec bx
014C: cmp si, bx
014E: jb 0142 ERR jb 0144
mov dx, 202
mov ah, 09
int 21
mov ah, 4C
int 21
n lab1.com
r cx
800
w
q
Tip1: ASCII codes are unsigned numbers. Therefore you should use the unsigned conditional branch instructions. I've used ja
JumpIfAbove and jae
JumpIfAboveOrEqual instead of jg
JumpIfGreater and jge
JumpIfGreaterOrEqual.
Tip2: If you would use AL instead of DL in those few new lines then the program would shorten by another 2 bytes. You could do this as an exercise, but remember that the branch targets would have to change accordingly, again!
0124: mov al, [bx] 2 bytes
0126: cmp al, 39 2 bytes
0128: ja 012E 2 bytes
012A: cmp al, 30 2 bytes
012C: jae 0136 2 bytes
012E: --------
10 bytes