彙編語言程序設計:[20]彙編計算器?

彙編語言(Assembly Language)是面向機器的程序設計語言。在彙編語言中,用助記符(Memoni)代替機器指令的操作碼,用地址符號(Symbol)或標號(Label)代替指令或操作數的地址,如此就增強了程序的可讀性並且降低了編寫難度,象這樣符號化的程序設計語言就是彙編語言,因此亦稱為符號語言。使用匯編語言編寫的程序,機器不能直接識別,還要由彙編程序或者叫彙編語言編譯器轉換成機器指令。彙編程序將符號化的操作代碼組裝成處理器可以識別的機器指令,這個組裝的過程稱為組合或者彙編。因此,有時候人們也把彙編語言稱為組合語言。

EMU8086是學習彙編必不可少的工具,它結合了一個先進的原始編輯器、組譯器、反組譯器、具除錯功能的軟件模擬工具(虛擬PC),還有一個循序漸進的指導工具。該軟件包含了學習彙編語言的全部內容。Emu8086集源代碼編輯器,彙編/反彙編工具以及可以運行debug的模擬器(虛擬機器)於一身,此外,還有循序漸進的教程。

工具/原料

Assembly Language emu8086(8086彙編模擬工具)

方法/步驟

下載安裝emu8086(8086彙編模擬工具),打開並運行軟件,新建文件命名為xiaobo calculator.asm

彙編語言程序設計:[20]彙編計算器

彙編語言程序設計:[20]彙編計算器

彙編語言程序設計:[20]彙編計算器

輸入如下代碼

;==給DD數x賦值的宏==將DD型的兩個數X,Y其中Y的值賦給X

give macro x,y

mov ax,y

mov x,ax

mov ax,y[2]

mov x[2],ax

endm

;**給DD數x賦值的宏**將DD型的兩個數X,Y其中Y的值賦給X

;==判斷正負宏== 判斷DD型x,y的正負利用fhx、fhy兩個常數記錄下並將

; 他們都化為正數方便運算

judge macro x,y

local judge1,judge2,judge3,judge4;;標號註釋,用於保證宏的重複調用

;;定位的標號不錯亂

mov ax,x

cmp ax,0

jge judge1

mov fhx,1;;記錄x的正負

neg x;;轉換為正數

judge1:

mov ax,x[2]

cmp ax,0

jge judge2

mov fhx,1

neg x[2]

judge2:

mov ax,y

cmp ax,0

jge judge3

mov fhy,1

neg y

judge3:

mov ax,y[2]

cmp ax,0

jge judge4

mov fhy,1

neg y[2]

judge4:

endm

;**判斷正負宏結束**

;==根據介入y值的0,1將x結果轉為正或負==

change macro x,y

local change1

cmp y,0

je change1

neg x

neg x[2]

change1:

endm

;**根據介入y值的0,1將x結果轉為正或負**

;==進位宏開始== 對小數部分除以100,將商進位,餘數補回小數

carry macro x

push cx;;免除對宏外面的cx,dx值造成干擾

push dx

mov ax,x[2]

mov cx,100

mov dx,0

div cx

mov x[2],dx

add x,ax

pop dx

pop cx

endm

;**進位宏結束**

;==新的加法宏開始== 算法,同號相加,異號相減

newadd macro x,y

local subsub,endnewadd,returnadd1,xbig,endadd1,endadd2,endadd3,endadda,endaddc

judge number3,number4;;不能直接代用x,y.

;;x其實既number3,y既number4。原因,下面一條註釋

mov ax,fhx

cmp fhy,ax

jne subsub

;;------兩個數符號相等則,直接兩部分相加

mov ax,y

add x,ax

mov ax,y[2]

add x[2],ax

carry number3

change number3,fhx

jmp endnewadd

;;---如果符號相反則,大數減去小數

subsub:

mov ax,y

cmp x,ax

ja xbig

jne endadda

mov ax,y[2]

cmp x[2],ax

ja xbig

endadda:

mov ax,x

sub y,ax

add y[2],100

mov ax,x[2]

sub y[2],ax

cmp y[2],100

jnb endadd1

sub y,1

jmp endaddc

endadd1:

sub y[2],100

endaddc:

give number3,number4

change number3,fhy

jmp endnewadd

xbig:

mov ax,y

sub x,ax

add x[2],100

mov ax,y[2]

sub x[2],ax

cmp x[2],100

jnb endadd2

sub x,1

jmp endadd3

endadd2:

sub x[2],100

endadd3:

change number3,fhx

jmp endnewadd

endnewadd:

mov fhx,0

mov fhy,0

endm

;**新的加法宏結束**

;==新的減法宏==

newsub macro x,y

mov fhx,1

change number4,fhx

mov fhx,0

newadd number3,number4

endm

;**新的減法宏**

;==新的乘法宏== 算法 (a1+b1)*(a2+b2)=a1*a2+a1*b2+a2*1+b1*b2

newmul macro x,y

judge number3,number4

push bx

push dx

mov bx,y

mov ax,x

mul bx

push ax;;壓棧用於後面的加法

mov ax,x[2]

mul bx

push ax;;正數部分乘小數部分的結果可以直接加到小數部分

mov bx,y[2]

mov ax,x

mul bx

push ax

mov ax,x[2]

mul bx

mov dx,0

mov bx,100;;小數部分乘小數部分的結果必需再縮小100倍,才

;;能再加回小數位

div bx

mov x[2],ax

pop ax

add x[2],ax

pop ax

add x[2],ax

pop ax

mov x,ax

carry number3

mov ax,fhy

xor fhx,ax

change number3,fhx

mov fhx,0

mov fhy,0

pop dx

pop bx

endm

;**新的乘法宏**

;==新的除法宏== 利用減法完成除法運送,但是為了減少逐減次數,所以

;先用a1/(a2+1)得要一個商,這個商一定不會大於逐減

;次數,所以就可以從(a1+b1)-商*(a2+b2)開始逐減,

;直到減出負數後,回加一個(a2+b2)得(a3+b3)。這時

;候的次數,就是結果的整數部分。最後將(a3+b3)*100

;按前面的方法,就可以得到,結果的兩位小數部分。

newdiv macro x,y

local endnewdiv

push bx

push dx

push cx

judge number3,number4

give fhdx,fhx

mov fhx,0

mov fhy,0

give divn4,number4

intdiv number3,number4;;求結果的整數部分

mov bx,100;;將減完的剩餘數擴大100倍

mov ax,number3

mul bx

mov number3,ax

mov ax,number3[2];;小數位擴大100倍,就等於直接進入整數位

add number3,ax

mov number3[2],0

give number4,divn4

intdiv number3,number4;;求結果的小數部分

pop number3[2]

pop number3

endnewdiv:

mov ax,fhdy

xor fhdx,ax

change number3,fhdx

mov fhdx,0

mov fhdy,0

pop cx

pop dx

pop bx

endm

;**新的除法宏**

;==除法的逐減宏==

intdiv macro x,y

local intdiv1,intdiv2,endintdiv;;內嵌宏,用於逐減

mov ax,x

mov bx,y

add bx,1

mov dx,0

div bx

push ax

mov bx,y

mul bx

mov y,ax

pop ax

push ax

mov bx,y[2]

mul bx

mov y[2],ax

carry number4

pop cx

newsub number3,number4

give number4,divn4;防止減法運算後改變的了number4的值

intdiv1:

newsub number3,number4

give number4,divn4

inc cx

cmp number3,0

jl endintdiv

je intdiv2

jmp intdiv1

intdiv2:

cmp number3[2],0

jl endintdiv

jmp intdiv1

endintdiv:

newadd number3,number4

dec cx

push cx

endm

;**除法的逐減宏**

;==設置光標宏==

curse macro cury,curx

mov ah,2

mov dh,cury

mov dl,curx

mov bh,0

int 10h

endm

;**設置光標宏**

;==定位字符串顯示宏==

menu macro op1,op2,op3 ;菜單顯示宏定義 將op3的內容顯示到op1,op2的位置

mov ah,02h

mov bh,00h

mov dh,op1

mov dl,op2

int 10h

mov ah,09h

lea dx,op3

int 21h

endm

;**定位字符串顯示宏**

;==清屏加色宏==

scroll macro n,ulr,ulc,lrr,lrc,att

mov ah,06

mov al,n;n=上卷行數;n=0時,整個窗口空白

mov ch,ulr;左上角行號

mov cl,ulc;左上角列號

mov dh,lrr;右下角行號

mov dl,lrc;右下角列號

mov bh,att;捲入行屬性

int 10h

endm

;**清屏加色宏**

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;程序開始

data segment

fhx dw 0;記錄x值的正負

fhy dw 0;記錄y值的正負

fhdx dw 0;記錄除法運算中的x值正負

fhdy dw 0;記錄除法運算中的y值正負

divn4 dd 0;除法中幫助暫存number4

number0 db 100;計入鍵盤輸入字符串

db 0

db 100 dup(0);

number dw 200 dup(0);存入輸入公式處

number2 dw 200 dup(0);讀取去括號後的公式暫存處

number3 dd 0;存儲用於計算的x數

number4 dd 0;存儲用於計算的y數

crx db 20;記錄光標列

cry db 10;記錄光標行

crx2 db 2;記錄光標列2

cry2 db 2;記錄光標行2

memb dw 0;記錄bx中的值是否儲存過

memx db 0;記錄是否應該進入小數存儲部分

memcl db 0;記錄已經存儲到小數的第幾位

rsi dw 0

begain db 'Xiaobo Welcome you to use the calculator!','$'

begain1 db 'data:2014/4/23','$'

begain2 db '****Designed by [email protected]!****','$'

begain3 db ' ;,'$'

begain4 db ' ^Henan University of Economics and Law^$','$'

begain5 db 'press "E" key to exit','$'

begain6 db 'press any key to contiune','$'

begain7 db 'Press "Enter" key to introudction','$'

help db 'Confine:32512.99~(-32768.00)','$'

help1 db 'Format: 1.32*99+(98.43/(-34))= ','$'

help2 db 'Notice 1:negative must like (-x)','$'

help3 db ' 2:only can abet double decimal fraction as 567.33','$'

help4 db 'press any key go on!','$'

error1 db ' Error!',13,10,'$'

DBUFFER DB 8 DUP (':'),12 DUP (' ');時間的底

data ends

code segment

assume cs:code,ds:data,es:data

start:

mov ax,data

mov ds,ax

mov ax,data

mov es,ax

;----歡迎界面-----

scroll 0,0,0,24,79,0;清屏

scroll 25,0,0,24,79,50h;開外窗口,品紅底

scroll 21,2,2,22,77,0fh;開內窗口,黑底白字

menu 4,20,begain

menu 6,20,begain1

menu 8,20,begain2

menu 10,20,begain3

menu 12,20,begain4

menu 14,20,begain5

menu 16,20,begain6

menu 18,20,begain7

mov ah,01

int 21h

cmp al,0dh;'Enter'

jne helpo

scroll 21,2,2,22,77,0fh;清屏,內窗

menu 6,20,help

menu 8,20,help1

menu 10,20,help2

menu 12,20,help3

menu 14,20,help4

mov ah,01

int 21h

scroll 21,2,2,22,77,0fh;清屏,內窗

jmp start1

helpo:

cmp al,45h;'E'

je exit

scroll 21,2,2,22,77,0fh;清屏,內窗

;----清零處理-----

start1:

call time

start3:

curse 10,25;光標定位中間

mov cx,200

mov si,0

sclear:

mov number[si],0

add si,2

loop sclear

mov cx,0

mov si,0

mov bx,0

mov crx,25

scroll 1,10,25,10,77,0fh;清除原來等式

;---開始----

call write

call loopcount

curse cry,crx

call output

mov ah,01

int 21h

scroll 1,cry2,2,cry2,77,0fh;清除原來等式

menu cry2,crx2,number0[2]

inc cry2

cmp cry2,10

jl start2

mov cry2,2

start2:

jmp start1

exit:

mov ah,4ch

int 21h

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;程序結束

;====寫入函數======

;數據格式:定義一個DD雙字數組,雙字的第一個字存數的整數部分,第二個字

; 存數的小數部分。但是為了最後的輸出方便,以及乘法運算的小數

; 部分運算後向整數部分進位,小數部分採用100進一制

;存數範圍:十進制32512.99~(-32767.00),十六進制7F00.63~8001.00(補碼)

;存數算法:整數部分 正數ai=ai*10+a(i+1),負數對正數求補碼

; 小數部分 正數bi=b1*10+b2,負數對正數求補碼

;存數說明:採用單個字符一個一個輸入的方式,字符為0~9時進入存數算法,當輸

; 入是運算符號時結束存數算法,並且開始存數及存運算符.但是這裡要

; 考慮一個問題不能每次有運算符號進入時都存數,比方A+((X)),如果每

; 次都存,A就會被存3次.所以這裡我們定義了一個常數remb記錄每個數存

; 入情況,方便存數時判斷

;負數處理:負數的介入要求格式為(-X),因為在讀取部分,會依次去括號,這樣就

; 變為了-X,所以只需要判斷一串公式開頭位'-'號,就知道介入的為負

; 數,再直接對X求補。(注:這步處理放在支持混合運算的si_ze宏部分)

;小數處理: 通過介入'.'來判斷是否開始存入小數部分

;特別說明: 1:由於運算符號的ASCLL較小,會與介入的數字相等,所以把運算符的

; ASCLL碼加上7F00H在存入,這樣也就要把7F00H~7FFFH預留給運算

; 符號,同時這也會導致存數範圍的縮小,不過個人覺得是值的.

;輸入格式: 按照平時正常等式的輸入方式輸入,以等號結尾.

; 例如:11*(1-3)/(-3)=

write proc near

;--寫入函數主部分----

startw:

lea dx,number0

mov ah,0ah

int 21h

xor cx,cx

mov cl,number0[1]

mov si,cx

add si,2

mov rsi,si

mov si,0

mov di,2

mov bx,0

startw2:

mov al,number0[di]

inc di

inc crx

mov ah,0

cmp al,45h;'E' 用於程序退出

jz exit

cmp al,2ah;'*'

jz memory;轉入存數及存運算符

cmp al,2fh;'/'

jz memory

cmp al,2bh;'/'

jz memory

cmp al,2dh;'-'

jz memory

cmp al,29h;')'

jz memory

cmp al,28h;'('

jz memory

cmp al,2eh;'.'

jz memoryx;轉入存入小數程序

cmp al,3dh;'='

jz memory

cmp al,0dh;'CR'

jz endwrite

sub al,30h;為存數算法做準備,讓'1'真正變成二進制碼的1

cmp al,0

jl error;報錯程序

cmp al,9

ja error

cmp memx,2

je error

cmp memx,1

je arithmeticx;小數存數算法程序

jmp arithmetic;整數存數算法程序

;---memory存入部分---

memory:

cmp memb,0;remb位0時表示數已經數存儲過;注:開始為remb賦值時

;也一定要為0,因為這是為了防止'(1+3)*4'這樣直接以運

;算符開始的等式

je memory1

mov number[si],bx;存入數

cmp memx,1;

je memory2;存小數部分程序

add si,4

gomemory1:

add ax,7f00h;將運算符轉換到7F00~7FFF之間

mov number[si],ax;存入運算符

mov memb,0;說明數已經存儲過

mov memx,0

mov memcl,0

mov bx,0

add si,4

loop startw2

jmp endwrite

memory1:;只存運算符號

add ax,7f00h

mov number[si],ax

add si,4

loop startw2

jmp endwrite

memory2:

add si,2

jmp gomemory1

;-memoryx小數存入部分-

memoryx:

mov memx,1;當remx為1時表示開始準備小數存入

mov number[si],bx

mov bx,0

add si,2;沒有加四,應為這下是要轉入存小數的下個字節

loop startw2

jmp endwrite

;-arithmetic存數算法--

arithmetic:

;算法bx=bx*10+ax

push ax

mov ax,bx

push cx

mov cx,10

mul cx

pop cx

pop bx

add ax,bx

mov bx,ax

mov memb,1;說明開始存數

cmp bx,7f00h;保證數在合適範圍內

jae error

loop startw2

jmp endwrite

;-arithmeticx存數算法--

arithmeticx:

cmp memcl,1

je arithmetix1

push cx

mov cx,10

mul cx

add bx,ax

pop cx

mov memb,1

inc memcl

loop startw2

jmp endwrite

arithmetix1:

add bx,ax

inc memcl

loop startw2

jmp endwrite

;---error報錯部分----

error:

curse cry,crx

lea dx,error1

mov ah,9

int 21h

jmp start1;重新運行程序

endwrite:

mov di,0

ret

write endp

;***寫入函數結束***

;===去括號函數=====

;程序說明:比方'11+(3+99)='這個等式,先從number的首位開始每隔兩個字取出數

; 與')'的現ASCLL碼7f29h比較從而找到第一個')'的位置,再到回去找到

; 最近的'('的位置,從而將中間沒括號的等式讀出到number3中,接著利

; 用si_ze函數算出這個等式的值,並且賦值回number中,以替代原來的括

; 號及括號能的等式

loopcount proc near

startlp:

mov bp,0

mov di,0

mov bx,0

mov si,0

startl:

mov ax,number[si]

cmp ax,7f29h

je rsee

add si,4

cmp ax,7f3dh

je lastl

jmp startl

rsee:

sub si,4

mov ax,number[si]

cmp ax,7f28h

je rwrite

jmp rsee

rwrite:

push si

; mov lct2,si

mov di,0

add si,2

rwrite1:

add si,2

mov ax,number[si]

mov number2[di],ax

cmp ax,7f29h

je rcount

add di,2

jmp rwrite1

rcount:

push si

; mov lct1,si

call si_ze

pop ax

pop di

push ax

; mov di,lct2

mov ax,number3

mov number[di],ax

mov number3,0

mov ax,number3[2]

add di,2

mov number[di],ax

mov number3[2],0

pop si

; mov si,lct1

add si,2

rcount1:

add si,2

add di,2

mov ax,number[si]

mov number[di],ax

cmp ax,7f3dh

je startlp

jmp rcount1

lastl:

mov si,0

lastll:

mov ax,number[si]

mov number2[si],ax

add si,2

cmp ax,7f3dh

je endl

jmp lastll

endl:

call si_ze

ret

loopcount endp

;**去括號函數結束**

;==混合四則運算函數==

;說明: 通過先不處理加減,先把乘除運算進行,將算出的結果帶回原來

; 的地方取代。最終得到一個只有加減的公式。來方便運算

;特別說明: 本運算還承貸著將(-1)轉為ffffh存入number中,既負數輸入

si_ze proc near

mov si,4

mov ax,number2

cmp ax,7f2dh;'-'

jne sstart

give number3,number2[4]

mov fhx,1

change number3,fhx

mov fhx,0

jmp end4ze

sstart:

mov ax,number2[si]

cmp ax,7f2ah;'*'

je mull;計算乘法

cmp ax,7f2fh;'/'

je divv

cmp ax,7f3dh;'='

je sznext;去完乘除後跳轉

cmp ax,7f29h;')'

je sznext

add si,4

jmp sstart

mull:

sub si,4

give number3,number2[si]

add si,8

give number4,number2[si]

newmul number3,number4

sub si,8

give number2[si],number3

call sloop

jmp sstart

divv:

sub si,4

give number3,number2[si]

add si,8

give number4,number2[si]

newdiv number3,number4

sub si,8

give number2[si],number3

call sloop

jmp sstart

sznext:

give number3,number2

mov si,0

sznext1:

add si,4

mov ax,number2[si]

cmp ax,7f2bh

je addd

cmp ax,7f2dh

je subb

cmp ax,7f3dh

je end4ze

cmp ax,7f29h

je end4ze

jmp sznext1

addd:

add si,4

give number4,number2[si]

newadd number3,number4

jmp sznext1

subb:

add si,4

give number4,number2[si]

newsub number3,number4

jmp sznext1

end4ze:

RET

si_ze endp

sloop proc near;用於循環賦值

mov di,si

add si,8

sloop1:

add di,4

add si,4

mov ax,number2[si]

push ax

give number2[di],number2[si]

pop ax

cmp ax,7f3dh;等號

je endsloop

cmp ax,7f29h;括號

je endsloop

jmp sloop1

endsloop:

ret

sloop endp

;**混合四則運算結束**

;==輸出函數==;通過除十取餘的方法,將數從低位到高位逐一取出再加30h轉為

; ascll輸出。注:先判斷數的正負來考慮是否輸出符號,接著輸出

; 整數部分再輸出一個“.”小數點最後輸出小數部分

output proc near

mov si,rsi

judge number3,number4

cmp fhx,1

jne output1

mov number0[si],2dh

inc si

mov dx,2dh

mov ah,02h

int 21h

output1:

mov ax,number3

mov bx,10

mov cx,0

call intoutput

mov number0[si],2eh

inc si

mov dx,2eh;輸出小數點

mov ah,02h

int 21h

mov ax,number3[2]

mov bx,10

mov cx,0

call intoutput

mov number0[si],'$'

ret

output endp

intoutput proc near

output2:

mov dx,0

div bx

push dx

inc cx

cmp ax,0

je output3

jmp output2

output3:

pop ax

add ax,30h

mov number0[si],al

inc si

mov dx,ax

mov ah,02

int 21h

loop output3

ret

intoutput endp

;**輸出函數**

CRLF PROC NEAR ;回車、顯示功能過程定義,屬性為NEAR

MOV DL,0DH ;把回車的ASCII碼0DH傳給DL

MOV AH,02H ;送DOS 的中斷調用功能號

INT 21H ; DOS 的中斷調用

MOV DL,0AH ; 把換行的ASCII碼0AH傳給DL

MOV AH,02H ; 送DOS 的中斷調用功能號

INT 21H ; DOS 的中斷調用

RET ; 返回

CRLF ENDP ;完成過程定義

TIME PROC NEAR ;顯示時間子程序

DISPLAY1:MOV SI,0

MOV BX,100

DIV BL

MOV AH,2CH ;取時間

INT 21H

MOV AL,CH

CALL BCDASC ;將時間數值轉換成ASCII碼字符

INC SI

MOV AL,CL

CALL BCDASC

INC SI

MOV AL,DH

CALL BCDASC

MOV BP,OFFSET DBUFFER

MOV DX,161dH

MOV CX,8

MOV BX,004EH

MOV AX,1301H

INT 10H

MOV AH,02H

MOV DX,0300H

MOV BH,0

INT 10H

MOV BX,0018H

RE: MOV CX,0FFFFH

REA: LOOP REA

DEC BX

JNZ RE

MOV AH,01H

INT 16H

JE DISPLAY1

JMP start3

RET

TIME ENDP

BCDASC PROC NEAR ;時間數值轉換成ASCII碼字符子程序

PUSH BX

CBW

MOV BL,10

DIV BL

ADD AL,'0'

MOV DBUFFER[SI],AL

INC SI

ADD AH,'0'

MOV DBUFFER[SI],AH

INC SI

POP BX

RET

BCDASC ENDP

code ends

end start

彙編語言程序設計:[20]彙編計算器

彙編語言程序設計:[20]彙編計算器

在彙編器選項中選擇編譯文件,編譯分為五個階段,生成一系列文件 debug 文件 list文件 symbol文件 和執行文件exe文件

彙編語言程序設計:[20]彙編計算器

彙編語言程序設計:[20]彙編計算器

彙編語言程序設計:[20]彙編計算器

彙編語言程序設計:[20]彙編計算器

彙編語言程序設計:[20]彙編計算器

彙編語言程序設計:[20]彙編計算器

彙編語言程序設計:[20]彙編計算器

執行編譯生成的xiaobocalculator.exe,可以看到如下界面 顯示的作者的個人信息和執行方法 press "E" key to exit press any key to contiune Press "Enter" key to introudction

Xiaobo Welcome you to use the calculator!

data:2014/4/23

****Designed by [email protected]!****

^Henan University of Economics and Law^

press "E" key to exit

press any key to contiune

Press "Enter" key to introudction

彙編語言程序設計:[20]彙編計算器

按enter繼續操作出現如下第一個界面,再enter出現操作界面,下角有時間顯示與系統時間同步

彙編語言程序設計:[20]彙編計算器

彙編語言程序設計:[20]彙編計算器

彙編語言程序設計:[20]彙編計算器

在這個界面中輸入 4344/2= 按enter就會出現答案如下

例43.43*44= 3*(4*(13-9))= 78.432/(4.53*(14-9+4-4-4))=

彙編語言程序設計:[20]彙編計算器

彙編語言程序設計:[20]彙編計算器

彙編語言程序設計:[20]彙編計算器

彙編語言程序設計:[20]彙編計算器

彙編語言程序設計:[20]彙編計算器

部分, 計算器, 彙編, 小數, 程序設計,
相關問題答案