汇编课程设计(二)--连续平方差
程序员文章站
2022-04-18 20:57:41
...
汇编课程设计(二)–连续平方差
基本要求
1、从键盘上输入一串表达式,程序能够解析表达式并求出对应的值
2、表达式的操作数为小于100的十进制正整数(个数不限)
3、运算符为^(求平方)和-(求差),前者的优先级高于后者
系统模块设计
流程图
源代码
data segment
Exp db 20,?,20 dup(?)
oper db 0;用于存放双目运算符
sign db '+'
InMsg db 'Please input the expression for square error:',13,10,'$'
OutMsg db 'The result is:',13,10,'$'
Ctrl db 13,10,'$'
InsPot db ?
data ends
code segment
assume cs:Code,ds:Data
start:
mov ax,Data
mov ds,ax
lea dx,InMsg
mov ah,9
int 21h
mov ax,'#'
push ax;将'#'压入堆栈,用于指示栈底
;输入表达式
ExpIn:
lea dx,Exp
mov ah,10
int 21h
;回车换行
lea dx,Ctrl
mov ah,9
int 21h
;设置循环次数和起始指针
mov cl,Exp[1]
mov si,2
;逐个字符解析表达式
LoopParse:
mov dl,Exp[si]
call Parse
inc si
dec cl
cmp cl,0
jnz LoopParse
lea dx,OutMsg
mov ah,9
int 21h
mov dl,sign
mov ah,2
int 21h
pop ax;将'#'弹出堆栈
pop ax
call Output
MOV AH,4CH
INT 21H
;解析表达式的子函数
Parse proc near
pop ax
mov InsPot,al
cmp dl,'^'
jz Squ
cmp dl,'-'
jz Subtra
;经过前面的比较之后,后面进行数据的处理
;判断oper单元中是否存放了双目运算符,如果存放了,则先将数据给压入栈中
;此时栈中会有两个元素,代表双目运算的操作数
;根据运算符来选择调用相关的子函数
;mov bl,oper
;cmp bl,0
;jnz HavOpr;如果不等于0,则说明已经有运算符
pop bx
cmp bx,'#'
jnz IsDec;将栈顶元素出栈,如果和栈底元素不相等,说明输入的是两位数
push bx;如果弹出来的是'#',则将'#'重新压入堆栈
sub dl,30h
push dx;否则将个位数压入堆栈
mov al,InsPot
xor ah,ah
push ax;将IP指针压入堆栈
ret
IsDec:
;bl中存放的是之前压入的个位数,这里应该让其乘以10,再加上
;新输入的数,组成两位数,将两位数压入堆栈
sub dl,30h
mov al,bl
mov bl,10
mul bl
add ax,dx
push ax
mov al,InsPot
push ax
ret
Subtra:
mov oper,dl
mov al,InsPot
push ax
ret
;计算平方
Squ:
pop ax;如果是单目运算符的话,就把操作数弹出堆栈
mul al;这里相当于求平方,然后将其结果保存到ax中
push ax;将结果压入堆栈中
cmp oper,'-';判断前面的字符是否含有减号
jz SubIt;如果含有则开始做减法
mov bx,'#'
push bx
mov al,InsPot
xor ah,ah
push ax
ret
;做减法
SubIt:
mov oper,0;将操作符重置
pop bx;减数
pop ax;将#弹出堆栈
pop ax;被减数
cmp sign,'-';如果符号位为负,则将被减数取反
jz Negation
Normal:
cmp ax,bx;比较被减数和减数的大小
jl Exc
Work:
sub ax,bx
push ax
mov bx,'#'
push bx
mov al,InsPot
xor ah,ah
push ax
ret
Exc:
xchg ax,bx
mov sign,'-'
jmp work
Negation:
neg ax
jmp Normal
Parse endp
Output proc near
mov bx,10;每次除以10,将10放进bx中
mov cx,0;计数,相当于有几位数
next:
mov dx,0
div bx
add dl,'0'
push dx;余数在dx中,将其放进栈中
inc cx;计数加一,相当于有多少位数
cmp ax,0;与0比较如果还不为0就继续执行操作
jnz next
mov ah,2
loop1:
pop dx;//输出
int 21h
loop loop1
ret
Output endp
code ends
end start
运行结果
心得
利用数据结构中的算法思想,我将表达式中的运算符分为单目运算符和双目运算符,将栈中的数据用#
隔开方便后续的算法处理。每计算一次就将结果压入栈中,这样循环往复就可以完成计算n位数平方差的过程。计算差的时机是在数据段中保存着之前解析的表达式中含有减号且这次解析的符号是平方。将算法列出流程图以后,编写程序起来就变得简单了。
在这个程序中遇到的问题比之前多得多,但我都通过DEBUG将其解决。最关键的一点是,我没有意识到ret语句其实也隐含着出栈的操作,如果没有正确处理子过程返回的代码段地址,那么便会将正确的数据给误弹出栈,于是我想到将调用处的IP值保存在数据段中,需要使用ret语句则将IP重新压入栈中。后面出现的一些计算结果不正确的错误,都是由于算法没有涉及周到导致的,我通过单步跟踪寄存器的值,发现了这些问题的所在之处,并完善了相应的算法。
推荐阅读