如何在 emu8086 中不使用减法或加法将小写字母转换为大写字母,反之亦然
How to convert lower case to upper case and vice versa without using subtraction or addition in emu8086
在汇编中,小写到大写或大写到小写的转换很容易。如果输入是小写字母,则加上 32d 将得到大写字母或者如果输入是大写字母,则减去 32d 将得到小写字母。但我想在不使用减法或加法的情况下进行此转换。
这是一个有趣的观察,如果您查看 ascii a~z
的二进制值,您会发现它们的第 6 位都设置为 1
。并且所有 ascii A~Z
的第 6 位都设置为 0
。并且保持所有位都相同。看看:
a = 01100001 z = 01111010
A = 01000001 Z = 01011010
^ ^
现在,第 6 位二进制值为 32 (00100000
)。所以,如果我们可以对小写或大写字母进行 xor
操作,那么它就会转换。很容易记住:32d
与从上到下或从下到上有关。 这里是演示代码:
; Here at first, @ indicating start of label and $ indicating start of procedure.
; If multiple label and procedure is present in assembly code.
; Then distinguishing label & procedure can be done easily.
; It's just my own way of coding. You may ignore this style.
.model small ; declaring this code will be consists of one data segment and one code segment
.stack 100h ; stack is initializeed to offset address at 100h
.data ; starting of Data segment
n_line db 0ah,0dh,"$" ; for new line
input_msg db "Input",20h,": $" ; 20h = 32d = ascii 'space'
output_msg db 0ah,0dh,"Output: $"
stop_msg db "Press 'esc' to Stop this Programme.",0ah,0dh,"$"
end_msg db 0ah,0dh,"Proramme Terminated. $"
warning_msg db 0ah,0dh,"Input is not a letter. Try agian.",0ah,0dh,"$"
.code ; starting of Code segment
main proc
mov ax,@data ; copying starting address of data segment into ax register
mov ds,ax ; by copying ax into ds we are initializing data segment
lea dx,stop_msg
mov ah,9
int 21h
@input:
mov cx,0
lea dx,input_msg
mov ah,9
int 21h
mov ah,1 ; taking single input charachter
int 21h
cmp al,27d ; cheking if it input is 'esc' or not
je @terminate
call $check_constraints ; procedure calling
cmp cx,1 ; cheking flag value
je @input
xor bx,bx ; XOR with self will always retun of all zero bit (means clearing a register)
mov bl,al
xor bl,32d ; Here is the bit trick
@output:
lea dx,output_msg
mov ah,9
int 21h
mov dl,bl ; output char was stored in bl
mov ah,2
int 21h
lea dx,n_line ; new line for next input
mov ah,9
int 21h
jmp @input
@terminate:
lea dx,end_msg
mov ah,9
int 21h
mov ah,4ch ; terminate program
int 21h
main endp ; ending of main procedure
$check_constraints proc
; if( (input<= 122d && input <= 97d) || (input<=90d && input <= 65d)) Then Proceed; otherwise Warning;
@first_if:
cmp al,122d ; or cmp al,'z'
jg @warning
cmp al,97d ; or cmp al,'a'
jge @setFlag
@second_if:
cmp al,90d ; or cmp al,'Z'
jg @warning
cmp al,65d ; or cmp al,'A'
jl @warning
@setFlag:
mov cx,0 ; i'm considering cx register as a flag
jmp @end_function
@warning:
mov cx,1 ; i'm considering cx register as a flag
lea dx,warning_msg
mov ah,9
int 21h
@end_function:
ret
$check_constraints endp
end main ; ending of code segment
在汇编中,小写到大写或大写到小写的转换很容易。如果输入是小写字母,则加上 32d 将得到大写字母或者如果输入是大写字母,则减去 32d 将得到小写字母。但我想在不使用减法或加法的情况下进行此转换。
这是一个有趣的观察,如果您查看 ascii a~z
的二进制值,您会发现它们的第 6 位都设置为 1
。并且所有 ascii A~Z
的第 6 位都设置为 0
。并且保持所有位都相同。看看:
a = 01100001 z = 01111010
A = 01000001 Z = 01011010
^ ^
现在,第 6 位二进制值为 32 (00100000
)。所以,如果我们可以对小写或大写字母进行 xor
操作,那么它就会转换。很容易记住:32d
与从上到下或从下到上有关。 这里是演示代码:
; Here at first, @ indicating start of label and $ indicating start of procedure.
; If multiple label and procedure is present in assembly code.
; Then distinguishing label & procedure can be done easily.
; It's just my own way of coding. You may ignore this style.
.model small ; declaring this code will be consists of one data segment and one code segment
.stack 100h ; stack is initializeed to offset address at 100h
.data ; starting of Data segment
n_line db 0ah,0dh,"$" ; for new line
input_msg db "Input",20h,": $" ; 20h = 32d = ascii 'space'
output_msg db 0ah,0dh,"Output: $"
stop_msg db "Press 'esc' to Stop this Programme.",0ah,0dh,"$"
end_msg db 0ah,0dh,"Proramme Terminated. $"
warning_msg db 0ah,0dh,"Input is not a letter. Try agian.",0ah,0dh,"$"
.code ; starting of Code segment
main proc
mov ax,@data ; copying starting address of data segment into ax register
mov ds,ax ; by copying ax into ds we are initializing data segment
lea dx,stop_msg
mov ah,9
int 21h
@input:
mov cx,0
lea dx,input_msg
mov ah,9
int 21h
mov ah,1 ; taking single input charachter
int 21h
cmp al,27d ; cheking if it input is 'esc' or not
je @terminate
call $check_constraints ; procedure calling
cmp cx,1 ; cheking flag value
je @input
xor bx,bx ; XOR with self will always retun of all zero bit (means clearing a register)
mov bl,al
xor bl,32d ; Here is the bit trick
@output:
lea dx,output_msg
mov ah,9
int 21h
mov dl,bl ; output char was stored in bl
mov ah,2
int 21h
lea dx,n_line ; new line for next input
mov ah,9
int 21h
jmp @input
@terminate:
lea dx,end_msg
mov ah,9
int 21h
mov ah,4ch ; terminate program
int 21h
main endp ; ending of main procedure
$check_constraints proc
; if( (input<= 122d && input <= 97d) || (input<=90d && input <= 65d)) Then Proceed; otherwise Warning;
@first_if:
cmp al,122d ; or cmp al,'z'
jg @warning
cmp al,97d ; or cmp al,'a'
jge @setFlag
@second_if:
cmp al,90d ; or cmp al,'Z'
jg @warning
cmp al,65d ; or cmp al,'A'
jl @warning
@setFlag:
mov cx,0 ; i'm considering cx register as a flag
jmp @end_function
@warning:
mov cx,1 ; i'm considering cx register as a flag
lea dx,warning_msg
mov ah,9
int 21h
@end_function:
ret
$check_constraints endp
end main ; ending of code segment