编辑代码

SECTION .data
message:TIMES 255 db 0
lenX:dd 1 ;4byte
lenY:dd 1 ;4byte
prompt:db "Input: " ,0h
debug db 'Invalid', 0
Xarr: TIMES 255 dd 0 ; one byte each
Yarr: TIMES 255 dd 0 ;Xarr本身的地址就是数组开头,而Xend中存放的地址是数组尾,它是指针
Xend:dd 0 ;
Yend:dd 0 ;存放X,Y的结尾指针
resultArr:TIMES 255 dd 0 ;存放倒置的result
result:TIMES 255 dd 0 ;结果的数组(正向)
lenR:dd 5 ;4byte ;暂存结果的长度(有可以能比结果长度大一位)
zero :dd 0
enter:dd 0xa ;换行符
arrPointer:dd 0 ;用于遍历数组 
ret: dd 0 ;进位符,1为有进位,0为无进位
array:dd 12,4,16,1,0 ;used in debug
length:dd 5 
flag :dd 9
round:dd 0 ;用于暂存地址
Q:dd 'Q'
Xback:TIMES 255 dd 0 
Yback:TIMES 255 dd 0 ;这两个数组是XY数组的倒放
ifMul :dd 0 ;记录是否是乘法,若是,该位为1


SECTION .bss
 ;存放输入时的字符串
msgX:resb 255 
msgY:resb 255 
num:resd 1; used in debug
i:resd 1; used in debug
j:resd 1; used in debug

SECTION .text
global  _start


setIfMul:
    mov dword[ifMul],1
calXLen:
    mov ebx,message
    mov ecx,eax
    sub eax,ebx
    mov [lenX],eax  
    mov eax,ecx  ;还原eax
    jmp nextcharY ;不回原循环了,跳到循环Y的部分
;********************** 打印数组的函数
printArr:
    ;打印一个数组(数组每一位是4字节),长度放在length中,数组起始放在arrPointer中
    ;mov dword[length],5
    mov dword[i],0
loop:
    mov eax,[length]
    sub eax,[i]
    cmp eax,0
    jle endLoop
    mov ecx,[i]
    mov edx,[arrPointer]
    mov eax,[edx+4*ecx]
    add eax,'0'
    mov [num],eax
    mov ecx,num
    mov eax,4
    mov ebx,1
    mov edx,4  ;注意,这里一次性要输出四字节(数组的一位))
    int 80h
    mov eax,[i]
    inc eax
    mov [i],eax  ;自增1
    jmp loop
endLoop:
    ret
;--------------------------------
;***********************************处理错误输入
solveError:
    mov eax,4
    mov ebx,1
    mov ecx,debug
    mov edx,7
    int 80h

    call printEnter
    jmp input

;-----------------------------------------
;***************************************** 清空数组(4位一组的)
;参数: 把数组头的地址放在arrPointer中
    
clearArr:
    mov dword[i],0
loopClear:
    mov eax,[i]
    cmp eax,255
    jge endClear

    mov eax,[arrPointer]
    mov ebx,[i]
    shl ebx,2
    add eax,ebx
    mov dword[eax],0

    mov eax,[i]
    inc eax
    mov [i],eax
    jmp loopClear

endClear:
    ret



;----------------------------------------------

;***************************************** 清空message
    
clearMessage:
    mov dword[i],0
loopClearMessage:
    mov eax,[i]
    cmp eax,255
    jge endClearMessage

    mov eax,message
    mov ebx,[i]
    add eax,ebx
    mov dword[eax],0

    mov eax,[i]
    inc eax
    mov [i],eax
    jmp loopClearMessage

endClearMessage:
    ret

;********************* 非函数,跳转语句
resolveX:
;这里要判断一下是否也比Y长,若长,则跳出大循环
    mov ebx,[lenY]
    sub ebx,[i]
    cmp ebx,0
    jl endTraverse
    mov ebx, zero
    jmp resolveXback

resolveY:
    mov ecx, zero
    jmp resolveYback

;------------------------------

;************************* 进位时用的,仅用于加法
addCarry:
    mov dword[ret],1 ;把进位符设为1
    sub ecx,10
    mov ebx,[arrPointer]
    mov [ebx],ecx
    jmp returnCarry

addOne:
    inc ecx
    mov eax,[arrPointer]
    mov [eax],ecx
    mov dword[ret],0 ;进位符置零
    jmp returnAdd
;-------------------------------
;********************** 翻转字符串函数
turnAround:
;参数:eax指向数组头,length里存长度,round存空地开头
    mov dword[i],0
    mov ebx,[length]
    dec ebx
    shl ebx,2  ;*4
    add eax,ebx  ;eax指向数组末尾
.loop:
    mov ebx,[length]
    cmp ebx,[i]
    jle endl

    mov ebx,[eax]  ;存放当前要移的变量

    mov edx,[round]
    mov ecx,[i]
    mov [edx+4*ecx],ebx

    sub eax,4 ;回退一格 

    mov ebx,[i]
    inc ebx
    mov [i],ebx ;自增i
    jmp .loop
endl:
    ret

;-------------------------------------- 

;**************************************************处理只有一位的结果
resolveOneBitResult:
    mov eax,4
    mov ebx,1
    mov ecx,result
    mov edx,4
    int 80h
    jmp end

;-------------------------------------------------------------

;************************************** 输出换行键
printEnter:
    mov eax,4
    mov ebx,1
    mov ecx,enter
    mov edx,4
    int 80h
    ret
    

;----------------------------------------------

;************************************************处理前导0(即把输出的起始向后移动一格),并把结果的位数减1,仅用于加法
;-------------------------------

;************************** 乘法进位时用的
addNum:
;当有进位时,加到该位上
    add ecx,[ret]
    mov eax,[arrPointer]
    mov [eax],ecx
    mov dword[ret],0 ;进位符置零
    jmp returnAddMul
;--------------------------------------


;************************************************ 处理进位(对于乘法有大于1进位的情况)
;参数:把该位的数放在ecx中,arrayPointer中有该处的指针(eax空闲)
solveCarryInMul:
    mov dword[ret],0 
L1:
    cmp ecx,9
    jle endL1
    sub ecx,10
    mov eax,[arrPointer] ;原数组处减10
    mov [eax],ecx

    mov eax,[ret] 
    inc eax
    mov [ret],eax ;进位加1
    jmp L1
endL1:
    jmp returnCarryMul
;---------------------------------------------------


_start:

input:
;***************************************************
    
    call clearMessage
    
    mov eax,result
    mov [arrPointer],eax
    call clearArr


    mov eax,resultArr
    mov [arrPointer],eax
    call clearArr

    mov eax,Xarr
    mov [arrPointer],eax
    call clearArr

    mov eax,Yarr
    mov [arrPointer],eax
    call clearArr

    mov eax,Xback
    mov [arrPointer],eax
    call clearArr

    mov eax,Yback
    mov [arrPointer],eax
    call clearArr

    mov dword[ifMul],0

;--------------------------------------------------

;***********************************************step1:处理输入,将两个数字分别方别两个数组中(每个数字占4byte),并存入两个数字的长度

;prompt for X
    mov eax,4
    mov ebx,1
    mov ecx,prompt
    mov edx,7
    int 80h

;这里要一个字符一个字符的输入,否则不知道什么时候结束 唉……
    mov dword[i],0
loopInput:  ;注意!!! 结尾一定要加一个0xa ,否则之后处理中不知道字符串什么时候结束
    mov eax,message
    add eax,[i] ;计算出下一个字符放在哪里
    mov [num],eax
    mov eax,3
    mov ebx,0
    mov ecx,[num]
    mov edx,1
    int 80h

    ;如果输入的是回车,则结束循环
    mov eax,[num] ;此时eax中是该字符的地址
    mov ebx,[eax]
    cmp ebx,0xa
    je endLoopInput

    mov eax,[i]
    inc eax
    mov [i],eax
    jmp loopInput

endLoopInput:

    mov ebx, message        ; move the address of our message string into EBX
    mov eax, ebx        ; move the address in EBX into EAX as well (Both now point to the same segment in memory)

 ;判断字符串是否是“q”,若是,结束程序
    cmp byte[eax],'q'
    je end

    
    mov edx,Xarr ;edx中存放数组的首地址
    mov ecx,0 ;用于遍历数组
;遍历第一个数的
nextcharX:
    cmp     byte[eax], '/'
    jz      solveError
    cmp     byte[eax], '+'
    jz      calXLen
    cmp     byte[eax], '*'
    jz      setIfMul
    mov     ebx,0 ;清空ebx
    mov     bl,[eax]  ;放到ebx的低八位中
    sub     ebx,'0'
    mov     [edx+4*ecx],ebx
    inc     ecx
    inc     eax          ; 
    jmp     nextcharX        


nextcharY:
    mov edx,Yarr ;edx中存放数组的
    mov ecx,0 ;用于遍历数组
    inc eax
nextcharYSecond:
    cmp     byte[eax], 0xa   ; 到回车结束遍历
    jz      calculateLen        ; 结束字符串遍历
    xor     ebx,ebx 
    mov     bl,[eax]
    sub     ebx,'0'
    mov     [edx+4*ecx],ebx
    inc     ecx
    inc     eax            ; increment the address in EAX by one byte (if the zero flagged has NOT been set)
    jmp    nextcharYSecond        ; jump to the point in the code labeled 'nextchar'
 
calculateLen:
    mov     ebx,message
    sub     eax, ebx      
    
      
    
    
    
;calculate the length of Y
    mov [lenY],eax
    mov edx,[lenX]
    sub eax,edx
    dec eax
    mov [lenY],eax
;*********************************************** end of step1 

;************* debug step1
;print  length of Yarr
    ;mov eax,[lenY]
    ;mov [length],eax
    ;mov eax,Yarr
    ;mov [arrPointer],eax
    ;call printArr

;print length of Y

    ;mov eax,[lenX]
    ;add eax,'0'
    ;mov [num],eax
    ;mov ecx,num
    ;mov eax,4
    ;mov ebx,1
    ;mov edx,4
    ;int 80h
  
    ;mov eax,[lenY]
    ;add eax,'0'
    ;mov [num],eax
    ;mov ecx,num
    ;mov eax,4
    ;mov ebx,1
    ;mov edx,4
    ;int 80h

    ;mov eax,[lenX]
    ;mov [length],eax
    ;mov eax,Xarr
    ;mov [arrPointer],eax
   ; call printArr

;------------------------------------------------------------
;*****************************处理乘法跳转
    mov eax,[ifMul]
    cmp eax,1
    je MultiPart

;***************************************************************step2 add 
;**** 1.先把两个数组的结尾存到Xend、Yend中 ,这两个都是指针,不是真实地址,要二次取指
    mov eax,Xarr
    mov ebx,[lenX]
    dec ebx ;注意,队尾是begin+4*(len-1)
    shl ebx,2 ;左移两位,*4
    add eax,ebx
    mov [Xend],eax ;此时Xend指向arrX的队尾

    mov eax,Yarr
    mov ebx,[lenY]
    dec ebx ;注意,队尾是begin+4*(len-1)
    shl ebx,2 ;左移两位,*4
    add eax,ebx
    mov [Yend],eax ;此时Yend指向arrY的队尾
   
;debug
    ;mov ecx,[Xend]
    ;mov eax,[ecx]
    ;mov [num],eax
    ;mov ecx,'0'
    ;add ecx,[num]
    ;mov [num],ecx
    ;mov eax,4
    ;mov ecx,num
    ;mov ebx,1
    ;mov edx,4
    ;int 80h

;***** 2.将两数相加

;初始化变量   
    mov eax,resultArr
    mov [arrPointer],eax
    mov dword[i],0
traverseAdd:  ;循环完这个后resultArr是倒叙
    mov ebx,[lenX]
    sub ebx,[i]
    cmp ebx,0
    jle resolveX

    mov ebx,[Xend]
    mov eax,[i]
    shl eax,2 ;*4
    sub ebx,eax  ;此时ebx中存放Xarr当前位的值

resolveXback:
    mov ecx,[lenY]
    sub ecx,[i]
    cmp ecx,0
    jle resolveY

    mov ecx,[Yend]
    mov eax,[i]
    shl eax,2 ;*4
    sub ecx,eax ;此时ebx中存放Yarr当前位的值
resolveYback:
    mov edx,[ebx]
    add edx,[ecx] ;此时已经相加完一位
    mov eax,[arrPointer]
    mov [eax],edx
    add eax,4 
    mov [arrPointer],eax

    mov ebx,[i]
    inc ebx
    mov [i],ebx

    jmp traverseAdd
    
endTraverse:
    ;计算结果的长度
    mov eax,[i]
    mov [lenR],eax 

    mov eax,[lenR]
    inc eax
    mov [lenR],eax ;将lenR再加1,99+9的时候会出现位数不够
    

;(debug)
    ;mov eax,[lenR]
    ;mov [length],eax
    ;mov eax,resultArr
    ;mov [arrPointer],eax
    ;call printArr
;---------------------------------------------------------------

;******************************************************step3 处理进位
;处理进位-------------------------------------------
    mov eax,[lenR]
    mov dword[length],eax
    mov eax,resultArr
    mov [arrPointer],eax ;此时arrayPointer指向的是结果数组的起始位置
    mov dword[i],0
solveCarry:
    mov eax,[i]
    mov ebx,[length]
    cmp eax,ebx
    jge endSolveCarry ;i>=length,则跳出循环
    mov ebx,[arrPointer] ;ebx存的是result数组此时的指针
    mov ecx,[ebx] ;ecx存的是数组里该位的值
    mov edx,[ret]
    cmp edx,1
    je addOne ;如果有进位,则该位加1   
returnAdd:
    cmp ecx,9
    jg addCarry
returnCarry:
    mov eax,[i]
    inc eax
    mov [i],eax 
    mov eax,[arrPointer]
    add eax,4
    mov [arrPointer],eax
    jmp solveCarry

endSolveCarry:
;(debug)
    ;mov eax,[lenR]
    ;mov [length],eax
    ;mov eax,resultArr
    ;mov [arrPointer],eax
    ;call printArr


;--------------------------------------------------------
;******************************************************** step 4: 将结果数组翻转过来,并去除前导0

;翻转
    mov eax,resultArr
    mov ebx,[lenR]
    mov [length],ebx
    mov ebx,result
    mov [round],ebx
    call turnAround


;(debug)
    ;mov eax,[lenR]
    ;mov [length],eax
    ;mov eax,result
    ;mov [arrPointer],eax
    ;call printArr

;去除前导0

    mov dword[i],0
    mov eax,result
    mov [arrPointer],eax

    mov eax,[lenR]
    mov [num],eax

loopZeroInAdd:
    mov eax,[num]
    mov ebx,[i]
    sub eax,ebx
    cmp eax,1
    jle continuePrintAdd ;当只剩一位时要跳出

    mov eax,[arrPointer]
    mov ebx,[eax]
    cmp ebx,0
    jne continuePrintMul;如果没有前导,跳出

  

    mov eax,[arrPointer]
    add eax,4
    mov [arrPointer],eax

    mov eax,[i]
    inc eax
    mov [i],eax

    mov eax,[lenR]
    dec eax
    mov [lenR],eax

    jmp loopZeroInAdd
continuePrintAdd:

;注意! 移动的是arrPointer,不是result,result指代的地址是不会变的
;最终输出
    mov eax,[lenR]
    mov [length],eax
    call printArr
    call printEnter
    jmp input

;-------------------------------------------------------

;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ add的part结束

;******************************************************** 乘法部分
MultiPart:

;*************************************************step2 翻转两个字符串 翻转后的数组分别放在Xback和Yback中了
    ;先翻转两个数组
    ;翻转字符串前的准备工作
    ;存入字符串的长度
    mov eax,[lenX]
    mov dword[length],eax
    ;存入数组头
    mov eax,Xarr
    ;将空地的首地址存到round这块内存中(round是指针)
    mov edx,Xback
    mov [round],edx
    ;函数调用
    call turnAround

    mov eax,[lenY]
    mov dword[length],eax
    ;存入数组头
    mov eax,Yarr
    ;将空地的首地址存到round这块内存中(round是指针)
    mov edx,Yback
    mov [round],edx
    ;函数调用
    call turnAround


;############debug
    ;print  length of Yarr
    ;mov eax,[lenX]
    ;mov [length],eax
    ;mov eax,Yback
    ;mov [arrPointer],eax
    ;call printArr


;------------------------------------------------------------------------
;*******************************************step3: 两个嵌套循环(模拟手算,X与Y的每一位相乘载相加)
;先初始一下结果数组(最多为lenX+lenY位)
    mov eax,[lenX]
    add eax,[lenY]
    mov [lenR],eax 

    mov dword[i],0 ; 指向计算Y的哪一位,也用来看resultArr从哪一位开始相加
    mov dword[j],0 ; 指向计算Y的哪一位

;把两个数组的结尾存到Xend、Yend中 ,这两个都是指针,不是真实地址,要二次取指
    mov eax,Xarr
    mov ebx,[lenX]
    dec ebx ;注意,队尾是begin+4*(len-1)
    shl ebx,2 ;左移两位,*4
    add eax,ebx
    mov [Xend],eax ;此时Xend指向arrX的队尾

    mov eax,Yarr
    mov ebx,[lenY]
    dec ebx ;注意,队尾是begin+4*(len-1)
    shl ebx,2 ;左移两位,*4
    add eax,ebx
    mov [Yend],eax ;此时Yend指向arrY的队尾
    

loop1:
    mov eax,[i]
    cmp eax,[lenY]
    jge endLoop1
    ;把此时的各位数拿出来,放在num中
    mov ebx,[i]
    shl ebx,2 ;偏移量乘4
    mov eax,[Yend]
    sub eax,ebx  ;此时eax中的地址为Y的该位的地址
    mov ebx,[eax]
    mov [num],ebx ;解放ebx,将单位数存在num中
    mov dword[j],0 ; 指向计算Y的哪一位
    
  loop2:  ;mul:    al<-al*dl  (X的位是正着算的)

        mov eax,[j]
        cmp eax,[lenX]
        jge endLoop2

        ;把X中的该位找出来
        mov eax,[Xend]
        mov ebx,[j]
        shl ebx,2
        sub eax,ebx ;此时eax中存放的是X中该位的地址  找X中位置的过程也是倒序

        mov edx,0 ;清寄存器
        mov edx,[eax]
        mov eax,0 ;清寄存器
        mov eax,[num] ;存放在al中(mul要用)
        mul dl ;此时结果放在al中(即eax的低8位)
;加到[resultArr+4*i+4*j]中
        mov ecx,resultArr
        mov ebx,[i]
        shl ebx,2
        add ecx,ebx
        mov ebx,[j]
        shl ebx,2
        add ecx,ebx
        mov ebx,[ecx] ;ebx为此时resultArr中的值

        add ebx,eax ;eax为这一步要乘进去的值

        mov [ecx],ebx 

        mov eax,[j]
        inc eax
        mov [j],eax
        jmp loop2
  endLoop2:

    mov eax,[i]
    inc eax
    mov [i],eax
    jmp loop1
endLoop1:


;debug


    ;mov eax,[lenR]
    ;mov [length],eax
    ;mov eax,resultArr
    ;mov [arrPointer],eax
    ;call printArr


;------------------------------------------------------------

;*********************************************************** 处理进位

    mov eax,[lenR]
    mov dword[length],eax
    mov eax,resultArr
    mov [arrPointer],eax ;此时arrayPointer指向的是结果数组的起始位置
    mov dword[i],0
solveCarryMul:
    mov eax,[i]
    mov ebx,[length]
    cmp eax,ebx
    jge endSolveCarryMul ;i>=length,则跳出循环
    mov ebx,[arrPointer] ;ebx存的是result数组此时的指针
    mov ecx,[ebx] ;ecx存的是数组里该位的值
    mov edx,[ret]
    cmp edx,1
    jge addNum ;如果有进位 
returnAddMul:
    jmp   solveCarryInMul ;处理进位
returnCarryMul:
    mov eax,[i]
    inc eax
    mov [i],eax 
    mov eax,[arrPointer]
    add eax,4
    mov [arrPointer],eax
    jmp solveCarryMul

endSolveCarryMul:
;(debug)
    mov eax,[lenR]
    mov [length],eax
    mov eax,resultArr
    mov [arrPointer],eax
    ;call printArr


;--------------------------------------------------------
;******************************************************** step 4: 将结果数组翻转过来,并去除前导0
;翻转
    mov eax,resultArr
    mov ebx,[lenR]
    mov [length],ebx
    mov ebx,result
    mov [round],ebx
    call turnAround


;(debug)
    ;mov eax,[lenR]
    ;mov [length],eax
    ;mov eax,result
    ;mov [arrPointer],eax
    ;call printArr

;输出(去除前导零)--注意结果为0的情况
    mov dword[i],0
    mov eax,result
    mov [arrPointer],eax

    mov eax,[lenR]
    mov [num],eax

loopZero:
    mov eax,[num]
    mov ebx,[i]
    sub eax,ebx
    cmp eax,1
    jle continuePrintMul ;当只剩一位时要跳出

    mov eax,[arrPointer]
    mov ebx,[eax]
    cmp ebx,0
    jne continuePrintMul;如果没有前导,跳出

  

    mov eax,[arrPointer]
    add eax,4
    mov [arrPointer],eax

    mov eax,[i]
    inc eax
    mov [i],eax

    mov eax,[lenR]
    dec eax
    mov [lenR],eax

    jmp loopZero
continuePrintMul:

;注意! 移动的是arrPointer,不是result,result指代的地址是不会变的
;最终输出
    mov eax,[lenR]
    mov [length],eax
    call printArr
    call printEnter
    jmp input
;------------------------------------------------------------------



end:
    mov     ebx, 0
    mov     eax, 1
    int     80h