欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

汇编实验2.2 查找匹配字符串(附有详细注释和源代码和相关知识)

程序员文章站 2022-07-13 21:58:32
...

实验2.2 查找匹配字符串
实验要求:
程序接收用户键入的一个关键字以及一个句子。如果句子中不包含关键字则显示’No match!’;如果句子中包含关键字则显示‘Match’,且把该字在句子中的位置用十六进制数显示出来。

相关知识

1.为什么不能说直接 MOV DS,1000H 而是要通过AX设置首地址?
答:不可以,因为不允许将立即数直接传送到段寄存器,这是mov命令本身的限制。

2.汇编语言中,CBW指令有何功能?
答:CBW 字节转换为字指令执行的操作:AL的内容扩展到AH,形成AX中的字。
AL符号扩展为AX。在8086中CBW指令将AL的最高有效位D7扩展至AH,即:如果AL的最高有效位是0,则AH = 00,AL的最高有效位为1,则AH = FFH。AL不变。(即将AL的符号位移至AH)
CBW属符号扩展指令,它可以把8位扩展到16位,扩展前后两数的真值不变,主要用于数据类型不同时用符号扩展指令可以使得数据类型相同

3.汇编中的JS什么意思
JS(jump if sign),汇编语言中的条件转移指令。结果为负则转移
(https://zhidao.baidu.com/question/207589465.html 中有完整的各种转移指令解释)

4.汇编语言中的 offset什么意思
答:(1、OFFSET是将数值回送变量或标号的偏移地址值.
2.LEA是将数值回送变量或标号的有效地址值.
3.SEG, 汇编程序将回送变量或标号的段地址值.
4、LEA BX,LIST5、MOV BX,OFFSET LIST6、可以看出,LEA和OFFSET这两条指令在功能上是相同的,BX寄存器都可得到符号地址LIST的值,而且此时MOV指令的执行速度会比LEA指令更快。但是,OFFSET只能与简单的符号地址相连,而不能和诸如LIST[SI]或[SI]等复杂操作数相连。因此,LEA指令在取得访问变量的工具方面是很有用的。)

5.SHL是逻辑左移,右边的位补零,ROL是循环左移,左边移出的位补到右边

附带注释的源码

(为方便,注释用了//,其实用分号才对,最下面有没有注释的清洁的源代码)
;··································································································

实验2.2
;PROGRAM TITLE GOES HERE–search
;*******************************
datarea segment
mess1 db ‘Enter keyword:’,’mess2dbEnterSentence:,' mess2 db 'Enter Sentence:','
mess3 db ‘Match at location:’,’mess4dbNomatch!,13,10,' mess4 db 'No match!',13,10,'
mess5 db ‘match.’,13,10,’$ ’ //由于有match at,所以其实没有用到mess5
mess6 db ‘H of the sentence.’,13,10,’$ ’
;
stoknin1 label byte //相当于定义了一个结构体
max1 db 10
act1 db ? //由于用户还要输入回车,所以最多能输入的字符实际只有10-1=9个,
//返回给act1的是实际输入的字符个数,它定义为字节类型的,所以以后
//通过mov想把act1的值赋值给cx时,就要cbw,把字节转为字
stokn1 db 10 dup(?)
;
stoknin2 label byte
max2 db 50 //输入字符串最多为49个字符,加上最后的回车
act2 db ?
stokn2 db 50 dup(?)
datarea ends
;*********************************
prognam segment
;---------------------------------
main proc far
assume cs:prognam ,ds:datarea,es:datarea
start:
push ds
sub ax,ax
sub bx,bx
push ax
mov ax,datarea
mov ds,ax
mov es,ax
;MAIN PART-------------
lea dx,mess1 ;提示:输入关键字
mov ah,09
int 21h
lea dx,stoknin1 //mov ah,0ah的作用如下:

键盘输入到缓冲区 DS:DX=缓冲区首地址
(DS:DX)=缓冲区最大字符数 (DS:DX+1)=实际输入的字符数

mov ah,0ah
int 21h			
cmp act1,0     //没输入关键字,就退出到DOS中
je exit	        			

a10: ;输入句子
call crlf ;回车,换行
lea dx,mess2 //键盘输入到缓冲区和显示字符串,这两个功能调用都是 以 DS:DX为地址的。
mov ah,09
int 21h
lea dx,stoknin2
mov ah,0ah //键盘输入句子
int 21h
cmp act2,0
je nmatch //假如没有输入句子,那么也跳到nmatch上去
mov al,act1 //把关键字的长度赋值给al
cbw //cbw把字节转为字
mov cx,ax
push cx //把关键字的长度赋值给cx
mov al,act2
sub al,act1
js nmatch //jump if sign,负则转 若句子长度小于关键字长度,则转到nmatch
mov di,0
mov si,0
lea bx,stokn2; //stokn2 是输入的句子(的首地址),先把它放入bx中
inc al //将al+1,为什么?al中放句子的长度
a20:
mov ah,[bx+di] ;开始比较
cmp ah,stokn1[si] ;不等则转到bx+1 //这里di加1可以吗,不可以, //因为后面要用bx的内容减去句子的首地址,来得到匹配 //的位置,所以不匹配时bx+1,匹配时di+1
jne a30 ;bx+1
inc si
inc di //若当前相等,则把si和di都加1,继续
dec cx //将要继续比较的关键字长度减一,得到的新的cx的值是剩下的要 //比较的字符个数
cmp cx,0
je match //若没比较完,继续比较,否则关键字长度减为0后,匹配
jmp a20
a30: //若关键字的第一个字母和句子中的字母不相等,则跳转到a30这儿 //来,也就是把句子中应该比较的字母的地址下标加1,将继续 //要比较的句子中字母的个数(在al中)减一
inc bx
dec al
cmp al,0 //假如最后一个字母比较完都不匹配,那么跳转到nmatch
je nmatch
mov si,0
mov di,0
pop cx //先pop,后push,是为这种情况设计的:句子:mnabde eabc 关键字:abc
//这时第一处ab其实是不匹配的,但是前面的a20中已经修改了cx的值,所//幸我们已经把cx=3的值在a10中push进入了堆栈,所以此时pop cx会将栈顶内容弹出并放入cx中,cx又变为了3,为了再次出现这种“只匹配前一部分,并不完全匹配”的情况,cx的内容能正确地恢复到关键字的长度,所以再次将cx push进去。
push cx
jmp a20 //?为什么又跳转到开始比较的地方呢 答:当前不匹配,不代表一直不匹配,只要句子未结束,就要一直比较下去
exit:
call crlf
ret
nmatch: ;no match则输出No match
call crlf
lea dx,mess4
mov ah,09
int 21h
jmp a10 //再次输入一个句子
match: ;match则输出位置信息
call crlf
lea dx,mess3 //mess3 db ‘Match at location:’,’$’

mov ah,09
int 21h				
sub bx,offset stokn2      //用bx去减stokn2的偏移地址
inc bx			//这里加1,是为了让第一个字母处就匹配了,会显示1,而不是在					//0处匹配,上面的地址差值是从0开始,所以这里+1,然后再转换	
call trans 			
lea dx,mess6       //mess6 db 'H of the sentence.',13,10,'$ ',H是16进制的后缀

mov ah,09
int 21h                         
jmp a10        //输入句子

crlf proc near ;回车,换行
mov dl,0dh ;?不用先push dx吗?是的,若返回回去的上下文中没有用到dx,那也可以 不push呀
mov ah,2
int 21h
mov dl,0ah
mov ah,2
int 21h
ret
crlf endp
trans proc near ;转换为16进制,参考书上例6.3,执行trans时,bx中存放的 //是已经得到的匹配位置的二进制表示
mov ch,4 ;number of digits
rotate:
mov cl,4 ;set count to 4bits
rol bx,cl ;left digit to right //rol循环左移,把bx循环左移4位
mov al,bl ;mov to al
and al,0fh ;mask off left digit //取低四位,也就是前面二进制串中的高四位
add al,30h ;convert hex to ASCII
cmp al,3ah ;is it>9? 数字9的ASCii码为57d,也就是39h,3ah是9的下一个 //字符
jl printit ;jump if digit=0 to 9 //jump if less
add al,7h ;digit is A to F //是字母的话,就顺序执行printit,也会打印,是数字
//不用加7了,直接跳转到打印处
printit:
mov dl,al ;put ASCII char in DL
mov ah,2 ;Display Output funct //ah=02 显示输出DL=输出字符
int 21h ;call DOS
dec ch ;done 4 digits? //将ch-1,ch控制转换次数,最终要得到4个16 //进制数字
jnz rotate ;not yet
ret ;return from trans
trans endp ;
main endp
;----------------------------------
prognam ends
;**********************************
end start

;···············································································

源码:

;PROGRAM TITLE GOES HERE–search
;*******************************
datarea segment
mess1 db ‘Enter keyword:’,’mess2dbEnterSentence:,' mess2 db 'Enter Sentence:','
mess3 db ‘Match at location:’,’mess4dbNomatch!,13,10,' mess4 db 'No match!',13,10,'
mess5 db ‘match.’,13,10,’$ ’
mess6 db ‘H of the sentence.’,13,10,’$ ’
;
stoknin1 label byte
max1 db 10
act1 db ?
stokn1 db 10 dup(?)
;
stoknin2 label byte
max2 db 50
act2 db ?
stokn2 db 50 dup(?)
datarea ends
;*********************************
prognam segment
;---------------------------------
main proc far
assume cs:prognam ,ds:datarea,es:datarea
start:
push ds
sub ax,ax
sub bx,bx
push ax
mov ax,datarea
mov ds,ax
mov es,ax
;MAIN PART-------------
lea dx,mess1 ;输入关键字
mov ah,09
int 21h
lea dx,stoknin1
mov ah,0ah
int 21h
cmp act1,0
je exit
a10: ;输入句子
call crlf
lea dx,mess2
mov ah,09
int 21h
lea dx,stoknin2
mov ah,0ah
int 21h
cmp act2,0
je nmatch
mov al,act1
cbw
mov cx,ax
push cx
mov al,act2
sub al,act1
js nmatch
mov di,0
mov si,0
lea bx,stokn2;
inc al
a20:
mov ah,[bx+di] ;开始比较
cmp ah,stokn1[si] ;不等则转到bx+1
jne a30 ;bx+1
inc si
inc di
;inc bx
dec cx
cmp cx,0
je match
jmp a20
a30:
inc bx
dec al
cmp al,0
je nmatch
mov si,0
mov di,0
pop cx
push cx
jmp a20
exit:
call crlf
ret
nmatch: ;no match则输出No match
call crlf
lea dx,mess4
mov ah,09
int 21h
jmp a10
match: ;match则输出位置信息
call crlf
lea dx,mess3
mov ah,09
int 21h
sub bx,offset stokn2
inc bx
call trans
lea dx,mess6
mov ah,09
int 21h
jmp a10
crlf proc near ;回车,换行
mov dl,0dh
mov ah,2
int 21h
mov dl,0ah
mov ah,2
int 21h
ret
crlf endp
trans proc near ;转换为16进制,参考书上例6.3
mov ch,4 ;number of digits
rotate: mov cl,4 ;set count to 4bits
rol bx,cl ;left digit to right
mov al,bl ;mov to al
and al,0fh ;mask off left digit
add al,30h ;convert hex to ASCII
cmp al,3ah ;is it>9?
jl printit ;jump if digit=0 to 9
add al,7h ;digit is A to F
printit:
mov dl,al ;put ASCII char in DL
mov ah,2 ;Display Output funct
int 21h ;call DOS
dec ch ;done 4 digits?
jnz rotate ;not yet
ret ;return from trans
trans endp ;
main endp
;----------------------------------
prognam ends
;**********************************
end start

————————————————

运行结果:

汇编实验2.2 查找匹配字符串(附有详细注释和源代码和相关知识)

相关标签: 匹配字符串