汇编实战!手把手教你从“计算器”入门汇编语言

发布时间 2023-10-12 23:40:04作者: 码dao成功
  • 基于汇编语言的简单整数计算器设计与实现

 

(此代码仅供学习使用,请勿用作其他用途)

摘要

本论文介绍了一款使用汇编语言编写的简单整数计算器程序,该程序支持基本的四则运算操作,并能处理包含括号的数学表达式。本文通过分析程序的代码结构,宏定义、数据段、子程序以及关键功能的实现,详细介绍了其设计与实现。同时,还讨论了程序的输入输出流程、符号优先级处理、运算逻辑、错误处理机制等方面的内容,以及代码中所使用的宏定义的功能。通过本文的阐述,读者将能够了解汇编语言中如何实现一个简单但完整的计算器程序。

引言

计算器是现代计算机科学中的一个重要应用,能够进行数学运算,解决各种实际问题。虽然现代计算器通常是软件应用程序,但在本文中,我们将介绍如何使用汇编语言设计和实现一个简单的整数计算器。该计算器能够执行加法、减法、乘法、除法等基本运算,同时支持使用括号改变运算的优先级。

 

数据段(Datas Segment)

程序的数据段包括字符串、标志、数值和运算符缓冲区。其中,字符串用于用户界面和错误信息的显示,标志用于跟踪输入状态,数值缓冲区用于存储数字,运算符缓冲区用于存储运算符和其优先级。这些数据段在程序运行时将用于输入、输出和计算。

宏定义

程序中使用了三个宏定义,分别是showfqhchh。这些宏用于实现代码的复用和简化,使代码更加易读。show宏用于显示字符串,fq宏用于为运算符赋权值,hchh宏用于在控制台输出时添加回车换行。

主程序(Main Procedure)

主程序是程序的入口点,它包括初始化数据段、显示用户界面、处理用户输入、进行运算和输出结果。主程序使用循环来不断接收用户输入,并根据用户的操作执行相应的计算和输出。如果用户输入的表达式不合法,程序会进行错误处理并提供相应的错误提示。

子程序(Procedures)

程序中包含了多个子程序,用于实现不同的功能。其中,dyfq子程序用于为运算符赋予优先级,output子程序用于输出计算结果,ys子程序用于执行实际的运算操作。这些子程序提高了代码的可维护性和模块化程度。

运算逻辑

程序使用栈来处理运算符的优先级。栈中存储了运算符和它们的优先级,通过比较运算符的优先级来决定执行哪个运算。程序会根据用户输入的数学表达式,依次处理数字和运算符,同时根据运算符的优先级进行相应的计算。

错误处理

程序实现了错误处理机制,当用户输入的表达式存在括号不匹配、运算符不合法或其他错误情况时,程序会输出错误提示信息,并允许用户重新输入。这增加了程序的健壮性和用户友好性。

 

datas segment
       str1     db 0ah,0dh,'*******************************************$'
       str2     db 0ah,0dh,'*          1   2   3   4   5              *$'
       str3     db 0ah,0dh,'*          6   7   8   9   0              *$'
       str4     db 0ah,0dh,'*          +   -   *   /   =              *$'
       str5     db 0ah,0dh,'*******************************************$'
       str6     db 0ah,0dh,  'please input a formula:  $'
       str7     db 'continue(y/n)$'
       sign1    dw 0                                                            ;值为0代表输入的不是数字,为1代表输入的是数字
       sign2    dw 0,0                                                          ;值为0代表输入的符号是匹配的,为1输入的符号不匹配
       number   dw 20 dup(0)                                                    ;保存输入的数值
       operator db '$'                                                          ;判断输入的运算符是否为空
                db 10 dup(0)                                                    ;保存该运算符对应的权值
       error    db 'wrong!$'
datas ends

STACKS SEGMENT
       
STACKS ENDS

show macro str               ;宏定义,显示字符串
            lea dx,str
            mov ah,9
            int 21h
endm
fq macro ascii,a,b              ;宏定义,给运算符赋权值
            cmp al,ascii
            jne s&a
            mov ch,b
            jmp s7
endm
hchh macro                   ;宏定义,回车换行
            mov ah,2
            mov dl,0dh
            int 21h
            mov ah,2
            mov dl,0ah
            int 21h
endm

codes segment
main proc far
              assume cs:codes,ds:datas
       start:
              mov    ax,datas
              mov    ds,ax
              lea    di,number
              lea    si,operator
              show   str1
              show   str2
              show   str3
              show   str4
              show   str5
              show   str6
              mov    ax,0
              mov    bx,0
              mov    cx,0
              mov    dx,0
       start1:
              hchh
       input: mov    ah,1
              int    21h
              cmp    al,'='
              je     let0
              cmp    al,1bh
              je     exit
              cmp    al,28h                  ;第二种情况,第一次输入的与28h也就是‘(’比较
              jb     input                   ;小于28h=(则重新输入  因为不管数字还是符号都比(大
              cmp    al,39h
              ja     input                   ;大于39h=9则重新输入  再大也用不着
              cmp    al,2fh                  ;判断是数字还是符号
              jbe    let1                    ;是符号转入响应操作
              inc    word ptr sign1          ;是数字的话将数字标志位加1
              sub    al,30h                  ;ASCII码与数字差
              mov    ah,0
              xchg   ax,[di]                 ;mul用ax中数乘源操作数
              mul    bx
              mov    bx,10
              xchg   ax,[di]
              add    [di],ax
              jmp    input
              call   fun
              ret
main endp
fun proc near                                ;***********************************************************

       let0:  
              cmp    word ptr sign2,0        ;判断配对标志位
              je     let1                    ;经过左括号和右括号抵消为0则跳转
              jmp    let8                    ;否则跳转到bc显示输入错误
       let1:  
              cmp    word ptr sign1,0
              je     let2
              add    di,2                    ;
              mov    word ptr sign1,0        ;将数字标志位sign1复0
       let2:  
              call   dyfq                    ;设定优先级
              cmp    ch,5                    ;判断输入的符号是否是左括号
              jne    let3                    ;不是则判断输入的是否是右括号
              inc    word ptr sign2          ;是左括号,括号标志位sign2加1
       let3:  
              cmp    ch,1                    ;判断输入的是否是右括号
              jne    let4
              dec    word ptr sign2          ;是右括号,括号标志位减1
       let4:  
              cmp    byte ptr[si],'$'        ;判断运算符存储区是否为空
              je     let6
              cmp    ch,[si]                 ;[si]的内容为前一个符号或其权值
              ja     let6
              cmp    byte ptr[si],'('
              jne    let5
              dec    si
              jmp    input
       let5:  
              dec    si
              mov    cl,[si]
              call   ys                      ;判断是什么运算符并进行相应的计算
              jmp    let4
       let6:  
              cmp    ch,0                    ;判断是否是等号
              je     output
              cmp    ch,1
              je     input                   ;“)”不保存,输入下一个数
              inc    si
              mov    [si],al                 ;保存符号
              inc    si
              cmp    ch,5                    ;判断是否是左括号
              jne    let7
              mov    ch,2                    ;改变(的权值
       let7:  
              mov    [si],ch                 ;紧跟着保存符号的权值
              jmp    input
       let8:  
              lea    dx,error
              mov    ah,9
              int    21h
              jmp    exit
              ret
fun endp                                     ;**********************************************************************
dyfq proc                                    ;子程序dyfq调用宏fq,判断优先级
              fq     28h,1,5                 ;调用宏fq为(赋权值
       s1:    fq     29h,2,1                 ;调用宏fq为)赋权值
       s2:    fq     2ah,3,4                 ;调用宏fq为*赋权值
       s3:    fq     2fh,4,4                 ;调用宏fq为/赋权值
       s4:    fq     2bh,5,3                 ;调用宏fq为+赋权值
       s5:    fq     2dh,6,3                 ;调用宏fq为-赋权值
       s6:    fq     3dh,7,0                 ;调用宏fq为=赋权值
       s7:    ret
dyfq endp                                    ;*********************************************
       output:                               ;输出运算结果
              sub    di,2
              cmp    word ptr[di],0
              jge    k1
              neg    word ptr[di]            ;求负数的绝对值
              mov    dl,'-'
              mov    ah,2
              int    21h
       k1:    mov    bx,10000
              mov    cx,5
              mov    si,0
       k2:    mov    ax,[di]
              cwd                            ;字到双字符的扩展
              div    bx
              mov    [di],dx
              cmp    al,0
              jne    k3
              cmp    si,0
              jne    k3
              cmp    cx,1
              je     k3
              jmp    k4
       k3:    mov    dl,al
              add    dl,30h
              mov    ah,2
              int    21h
              mov    si,1
       k4:    mov    ax,bx                   ;实现进制转换
              mov    dx,0
              mov    bx,10
              div    bx
              mov    bx,ax
              loop   k2
              hchh
              show   str7
              mov    ah,1
              int    21h
              cmp    al,'n'                  ;判断是否继续输入,输入n则结束操作
              je     exit
              cmp    al,'N'
              je     exit
              mov    word ptr[di+2],0
              lea    di,number
              lea    si,operator
              jmp    start1
       exit:  
              mov    ah,4ch
              int    21h
ys proc near                                 ;子程序,进行相应的运算
              push   ax
              mov    ax,0
              mov    bx,0
              cmp    cl,2ah                  ;乘法运算
              jne    chu
              sub    di,2
              xchg   bx,[di]
              sub    di,2
              xchg   ax,[di]
              imul   bx
              mov    [di],ax
              add    di,2
              jmp    finish
       chu:  
              cmp    cl,2fh                  ;除法运算
              jne    jia
              sub    di,2
              xchg   bx,[di]
              sub    di,2
              xchg   ax,[di]
              cwd
              idiv   bx
              mov    [di],ax
              add    di,2
              jmp    finish
       jia:  
              cmp    cl,2bh                  ;加法运算
              jne    jian
              sub    di,2
              xchg   bx,[di]
              sub    di,2
              add    [di],bx
              add    di,2
              jmp    finish
       jian:  
              cmp    cl,2dh                  ;减法运算
              jne    finish
              sub    di,2
              xchg   bx,[di]
              sub    di,2
              sub    [di],bx
              add    di,2
       finish:
              pop    ax
              ret
ys endp                                      ;**************************************************************
codes ends
    end start
 
 
运行截图:
 

 

.