📄 txtfind.asm
字号:
;********************************************************
mov si,[otxStart] ;ds:si = ptr to txt table of opcode
;to start search with
or di,di ;is this a TxtSkip request?
jne NotSkipOp ;brif not
; We just want to skip one opcode in the text table.
; ds:si - points to opcode to skip.
lodsw ;ax = current opcode from text table
test [flags],TFC_FindExec
je SkipOpNotExec ;brif scanState == SS_EXECUTABLE
; map executor to opcode
xchg bx,ax ;bx = executor's adr
mov ax,es:[bx-2] ;ax = executor's opcode
SkipOpNotExec:
and ah,HIGH OPCODE_MASK ;upper bits sometimes used for operands
mov dx,ax
mov bx,dx ;bx = opcode
mov al,cs:[mpOpAtr_UNDONE + bx] ; al = #bytes of operands
and ax,OPA_CntMask ;Isolate attribute count
.errnz OPA_CntMask AND 0FF00H ;must use ax in next line if not
cmp al,OPA_CntMask ;Test for cnt field in operand
jne SkipNotVar ;brif variable length operand count
lodsw ;ax = # bytes of operands
inc ax ;round up to odd count as follows:
and al,-2 ; {0,1,2,3,4,...} => {1,3,3,5,5,...}
SkipNotVar:
add si,ax ;si points to next opcode
push ss
pop ds ;ds -> DGROUP
DJMP jmp SHORT FindExit
J1_FindOpExec:
DJMP jmp SHORT FindOpExec
; Search for first opcode in text table which matches an opcode specified
; in the search table.
NotSkipOp:
test [flags],TFC_FindExec
jne J1_FindOpExec ;brif scanState == SS_EXECUTABLE
test [flags],TFC_FindNext
je TestOp ;brif entry point was TxtFindOp[DS]
lodsw ;ax = current opcode from text table
and ah,HIGH OPCODE_MASK ;upper bits sometimes used for operands
mov dx,ax
;Register conventions for TxtFind loop
;ds:si - pts to current opcode in txt table
;ss:di - pts to base of search opcode bit array
;dx - current opcode
TryNext:
mov bx,dx ;bx = opcode
mov al,cs:[mpOpAtr_UNDONE + bx] ; al = #bytes of operands
and ax,OPA_CntMask ;Isolate attribute count
.errnz OPA_CntMask AND 0FF00H ;must use ax in next line if not
cmp al,OPA_CntMask ;Test for cnt field in operand
je VarLenOpcode ;brif variable length operand count
VarLenRet:
add si,ax ;si points to next opcode
TestOp:
lodsw ;ax=opcode to search for (from txt tbl)
and ah,HIGH OPCODE_MASK ;upper bits sometimes used for operands
; test to see if opcode bit is set in search table
mov dx,ax ;dx = current opcode
mov bx,ax
shr bx,1 ;divide opcode by 8 to get byte index
shr bx,1 ;into bit-packed array for this opcode
shr bx,1 ;bx=byte in bit packed array for opcode
and al,7 ;al = bit number in array byte
mov cl,al
mov al,1
shl al,cl ;al = bit mask for opcode in array byte
test ss:[di+bx],al ;test opcode bit for match
jz TryNext ;brif no match, try next opcode
; We have found the opcode. We reenter here from FindOpExec.
; si - pts two bytes past found opcode.
FoundOpcode:
dec si
dec si ;si points to found opcode
push ss
pop ds ;restore ds -> DGROUP
assumes ds,DGROUP
;es still points to CODE
mov di,[pOpcodeList] ;es:di = ptr to original list of opcodes
inc di
inc di ;advance past size of table to first op
mov cx,-1
xchg ax,dx ;ax = opcode found
repne scasw ;search for found opcode in table
not cx ;cx = index+1 into table where opcode
;was found
dec cx ;cx = index
DbAssertRel cx,be,[cOpcodes],CP,<Error In TxtFindOp: Incorrect opTable>
mov [txtFindIndex],cl ;return index for matched opcode in
; global static variable txtFindIndex
mov dl,cl ;return txtFindIndex in dl
FindExit:
xchg ax,si ;return offset in ax
DbSegMoveOn ;OK to move segs again
cEnd ;TxtFindOpcode
; We have a variable length opcode in SS_RUDE or SS_PARSE state.
; Pick up the byte count of the operands, and skip to the next opcode.
;
VarLenOpcode:
lodsw ;ax = # bytes of operands
inc ax ;round up to odd count as follows:
and al,-2 ; {0,1,2,3,4,...} => {1,3,3,5,5,...}
jmp SHORT VarLenRet
;********************************************************
;NOTE: DS register points to text table until end-of-loop
; ES points to CODE, where opcodes in execute state can be accessed
; SS still points to DGROUP, so local vars can be accessed
;********************************************************
assumes ds,NOTHING
; We are in SS_EXECUTE state. Search the pcode for an opcode from
; the passed table.
FindOpExec:
test [flags],TFC_FindNext
je TestOpExec ;brif entry point was TxtFindOp[DS]
lodsw ;ax = current opcode from text table
; map executor to opcode
xchg bx,ax ;bx = executor's adr
mov ax,es:[bx-2] ;ax = executor's opcode
and ah,HIGH OPCODE_MASK ;upper bits sometimes used for operands
mov dx,ax
;Register conventions for FinOpExec loop
;ds:si - pts to current opcode in txt table
;ss:di - pts to base of search opcode bit array
;es - pts to CODE seg for execute state searches
;dx - current opcode
TryNextExec:
mov bx,dx ;bx = opcode
mov al,cs:[mpOpAtr_UNDONE + bx] ; al = #bytes of operands
and ax,OPA_CntMask ;Isolate attribute count
.errnz OPA_CntMask AND 0FF00H ;must use ax in next line if not
cmp al,OPA_CntMask ;Test for cnt field in operand
je VarLenOpcodeExec ;brif variable length operand count
VarLenExecRet:
add si,ax ;si points to next opcode
TestOpExec:
lodsw ;ax=opcode to search for (from txt tbl)
; map executor to opcode
mov bx,ax ;bx = executor's adr
mov ax,es:[bx-2] ;ax = executor's opcode
and ah,HIGH OPCODE_MASK ;upper bits sometimes used for operands
; test to see if opcode bit is set in search table
mov dx,ax ;dx = current opcode
mov bx,ax
shr bx,1 ;divide opcode by 8 to get byte index
shr bx,1 ;into bit-packed array for this opcode
shr bx,1 ;bx=byte in bit packed array for opcode
and al,7 ;al = bit number in array byte
mov cl,al
mov al,1
shl al,cl ;al = bit mask for opcode in array byte
test ss:[di+bx],al ;test opcode bit for match
jz TryNextExec ;brif no match, try next opcode
jmp FoundOpcode
; We have a variable length opcode in SS_EXECUTE state.
; Pick up the byte count of the operands, and skip to the next opcode.
;
VarLenOpcodeExec:
lodsw ;ax = # bytes of operands
inc ax ;round up to odd count as follows:
and al,-2 ; {0,1,2,3,4,...} => {1,3,3,5,5,...}
jmp SHORT VarLenExecRet
assumes ds,DGROUP
;*************************************************************************
; TxtFindOpFar
; Purpose:
; Same as TxtFindOp, only has a FAR interface
;
;*************************************************************************
cProc TxtFindOpFar,<PUBLIC,FAR>
parmW otxStart
parmW pOpcodeList
cBegin
cCall TxtFindOp,<otxStart,pOpcodeList>
cEnd
;*************************************************************************
; TxtFindNextOpFar
; Purpose:
; Same as TxtFindNextOp, only has a FAR interface
;
;*************************************************************************
cProc TxtFindNextOpFar,<PUBLIC,FAR>
parmW otxStart
parmW pOpcodeList
cBegin
cCall TxtFindNextOp,<otxStart,pOpcodeList>
cEnd
;*************************************************************************
; TxtSkipOp
; Purpose:
; Skip over 1 opcode. Text table can be in any scan-state.
; Entry:
; grs.fDirect, grs.oRsCur identify text table
; ax = offset of opcode to be skipped
; Exit:
; ax = offset beyond skipped opcode
;
;*************************************************************************
cProc TxtSkipOp,<PUBLIC,NEAR>
cBegin
push ax
PUSHI ax,0
cCall TxtFindNextOp ;ax = result
cEnd
;*************************************************************************
; TxtSkipOpFar
; Purpose:
; Same as TxtSkipOp, only has a FAR interface, and otx is in BX
;
;*************************************************************************
cProc TxtSkipOpFar,<PUBLIC,FAR>
cBegin
xchg ax, bx ; ax = input value
cCall TxtSkipOp ;ax = result
cEnd
;*************************************************************************
; TxtChkValidOpsExec
; Purpose:
; Verify that expected opcodes exist in an oTx range. The text
; table is assumed to be in SS_EXECUTE state. Ensures that only
; white space and remarks come between a SELECT CASE and the
; first CASE, END SELECT clause.
; Entry:
; parm1: ushort oTxFirst - oTx of first opcode of interest.
; parm2: ushort oTxLast - oTx of last opcode of interest.
; Exit:
; ax = oTx of first opcode not found in list, or oTxLast if all opcodes
; valid.
; dx == 0 if all opcodes valid.
; Preserves:
; si, di
;*************************************************************************
cProc TxtChkValidOpsExec,<PUBLIC,FAR>,<si>
parmW oTxFirst
parmW oTxLast
cBegin
DbChk Otx,otxFirst
DbChk Otx,otxLast
mov ax,oTxFirst ;start at first opcode of interest
TxtChkValidLoop:
push ax ;stack oTxCur for Second TxtFind call
push ax
PUSHI ax,<codeOFFSET tOpSelect> ;get valid op table addr
call TxtFindNextOpExec ;ax = oTx of next opcode in list
pop bx ;recover oTxCur
cmp dl,SEL_opValidMax ;is op within valid range?
ja TxtChkValidX ;ax = oTx of bad guy, psw.z clear
xchg ax,si ;remember found opcode
push bx ;oTxCur
PUSHI ax,0 ;find next op (oTxCur already stacked)
cCall TxtFindNextOpExec ;ax = oTx of next opcode
cmp ax,si ;next opcode should have been in list
jnz TxtChkValidX ;brif not - offender in AX, psw.z clear
cmp ax,oTxLast ;more to search?
jb TxtChkValidLoop ;brif so.
cmp ax,ax ;all hunky dory - set psw.z
TxtChkValidX:
mov dx,sp
jnz @F ; brif not all opcodes valid
sub dx,dx
@@:
cEnd
;*************************************************************************
; LOCAL FindBol
; Purpose:
; Search the current text table from its start for a certain
; beginning of line opcode, given the following 2 stopping conditions:
; 1 - stop after cx beginning of lines have been seen,
; 2 - stop after going beyond a certain text offset
; NOTE: This routine is crucial for PageUp speed. Thus some code has been
; duplicated from TxtFindOpcode to help Page Up performance.
; Entry:
; ax = txt offset to stop at
; cx = line # to stop at
; Exit:
; grs.fDirect is reset to FALSE
; ax = text offset to beginning of line opcode
; dx = text offset to beginning of line opcode for previous line
; cx = initial cx - # lines skipped
; [fLnNotIncl] = zero if given line was an INCLUDEd line
;
; For example, if pcode contained:
; [0]opBol,[2]opStop,[4]opBol,[6]opStop,[8]opEndProg,[0A]opEot
; The following inputs would produce the following results:
; ax cx => ax cx dx
; 0000 FFFF => 0004 FFFF 0000
; 0001 FFFF => 0004 FFFF 0000
; 0002 FFFF => 0004 FFFF 0000
; 0003 FFFF => 0004 FFFF 0000
; 0004 FFFF => 0008 FFFE 0004
; 0005 FFFF => 0008 FFFE 0004
; 0006 FFFF => 0008 FFFE 0004
; 0007 FFFF => 0008 FFFE 0004
; 0008 FFFF => 0008 FFFE 0004
; FFFF 0000 => 0000 0000 0000
; FFFF 0001 => 0004 0000 0000
; FFFF 0002 => 0008 0000 0004
; FFFF 0003 => 0008 0000 0004
;
;*************************************************************************
StartFromTop:
xor ax,ax
mov [lnFindLast],ax ;set lnFindLast to line # zero
;We must search for the first Bol since the scanner can insert opNoList's
;before the first line.
push cx ;save skip line count
push ax
PUSHI ax,<CODEOFFSET tOpBol> ;pass ptr to start-of-line table
call TxtFindOp ;ax = offset to 1st opBos/opBol/opEot
pop cx ;restore cx = skip line count
mov dx,ax ;dx = offset of 0th line
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -