如何在 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