具体实验代码,search.asm如下:
;数据段
;**********************************************
datarea segment
string1 db "Enterkeyword:$"
string2 db "Entersentence:$"
string3 db "Matchat location:$"
string4 db "Nomatch!",13,10,"$"
string5 db "Hof the sentence.$"
keyword db 50D,?,50DDUP(?) ;0A功能调用:最大输入50个字符,实际输入个数,存放的字符
sentence db 50D,?,50DDUP(?)
datarea ends
;**********************************************
;代码段
;**********************************************
prognam segment
;----------------------------------------------
main procfar
assume ds:datarea,cs:prognam,es:datarea
start:
push ds
sub ax,ax
push ax
mov ax,datarea
mov ds,ax
mov es,ax
lea dx,string1 ;显示字符串1
mov ah,09h
int 21h
lea dx,keyword ;输入关键字
mov ah,0Ah
int 21h
mov ah,02h ;显示输出换行
mov dl,0Ah
int 21h
lea dx,string2 ;显示字符串2
mov ah,09h
int 21h
lea dx,sentence ;输入句子
mov ah,0Ah
int 21h
mov ah,02h ;输出换行
mov dl,0Ah
int 21h
lea si,keyword+2;从第三个字节开始
lea di,sentence+2
mov ax,0
mov al,[sentence+1]
mov ah,[keyword+1]
cmp al,ah ;比较关键字和句子的长度
;jnl right
jl wrong
;lea dx,string4
;mov ah,09h
;int 21h
;jmp exit
;right:
sub al,ah
mov ah,0
add al,1
mov cx,ax ;循环次数
compare:
push cx
; mov cx,ax
; cld ;使变址寄存器SI和DI的地址指针自动加1
; repz cmpsb
; jz match
;
; sub ax,cx
; sub si,ax
mov cx,3
cld
repz cmpsb
jz match
;未比较成功
mov ax,3
sub ax,cx
sub si,ax ;关键词回到词首
mov ax,2
sub ax,cx
sub di,ax
pop cx
loop compare
;----------------------------------------------------------------
wrong:
lea dx,string4
mov ah,09h
int 21h
jmp exit
;----------------------------------------------------------------
match:
pop cx
mov bx,di ;DI指向句子中字符串匹配成功的最后一个字符
lea dx,string3
mov ah,09h
int 21h
sub bx,offset sentence+2
sub bx,2 ;BX存入首地址所在字符串中的地址,即匹配到关键字的首位置
call change ;将位置用16进制数表示
lea dx,string5
mov ah,09h
int 21h
;----------------------------------------------------------------------
exit:
mov ah,4ch
int 21h
ret
main endp
;-----------------------------------------------------------
;附加段
;*****************************************************************************
change procnear
push ax
push bx
push cx
push dx
mov ch,4
mov cl,4
;-------------------------------------------------------------------------
rotate: ;把四位二进制数转换为ASCII码
rol bx,cl
mov al,bl
and al,0Fh
add al,30h
cmp al,3Ah
jl printit
add al,7h
;--------------------------------------------------------------------------
printit:
mov dl,al
mov ah,2
int 21h
dec ch
jnz rotate
pop dx
pop cx
pop bx
pop ax
ret
change endp
;****************************************************************************
prognam ends
;****************************************************************************
end start
该实验是查找匹配字符串,其难点有两处:
一个是将句子中匹配到的关键字的首地址16位二进制数表示为4位16进制数,这个问题在课本上有具体实例。我通过添加一个附加段change实现该功能,具体实现思路为,将dx中存储的16位二进制数依次进行四位的循环左移,将移入低位的高四位再进行加30h(另一种情况会再加7)操作,最后实现输出为4位16进制地址。
第二个问题是本实验的关键,在句子中查找是否存在之前输入的关键字。首先需要有输入限制要求,即输入的关键字长度不能大于句子的长度。然后是比较句子中的字符和关键字,利用cld依次将si、di增1,repz cmpsb比较si、di指向的字符,若三次比较均成功,则跳转至match(表示匹配成功),在match中实现将句子中匹配成功的首地址存放在bx中。否则继续下面的执行,恢复si指针指向关键字首地址,di指向句子的匹配失败的首地址的下一个地址,然后继续循环compare(继续寻找匹配),若最后失败则执行到wrong。
在该实验中,我犯了一个错误,将wrong的操作放在了关键字长度不小于句子长度的判断后面,如此,实际上在之后的匹配中,即使最后没有找到匹配成功的关键字,但程序会显示句子中最后一次尝试匹配的首地址。显然这是不正确的。