📄 nammgr.asm
字号:
mov cx,[bx.BD_cbLogical] ;byte count
DbAssertRel cx,be,CB_MAX_NAMENTRY,CP,<ONamOfPsd: psd.cb too large>
push dx ;put retval back on stack
cEnd <nogen> ;fall into ONamOfPbCb
;***
;ONamOfPbCb oNamW = ONamOfPbCb
;Purpose:
; To return the Name Table offset of a symbol. If the symbol isn't
; already in the Name Table, then it is added. The symbol's case is
; preserved in tNam , but it is ignored while searching for a match
; (FoO is the same as fOo). If the cases don't match exactly, then the
; new symbol will replace the old one in tNam by default; this replacement
; is suppressed if the Cb input word has it's high bit set. A 0 is
; returned in AX to indicate an error condition (out of memory, etc).
;Assumptions:
; )symbols can never be removed from tNam
; )Each char in the name part of the symbol can be any valid
; ASCII (0-127) except the following:
; <Control Char> < ' > < { > < | > < } > < ~ > <DEL>
; )0 < cb < CB_MAX_NAMENTRY
;Register conventions:
; DS - pbName segment
; ES - tNam segment
; SI - pbName pointer
; DI - tNam pointer
;Entry:
; AX = ptr to ASCII string
; CX = length of ASCII string
; If the high bit is set and the name is found, the existing
; name is NOT to be replaced in the table.
; The following globals are referenced
; mrsCur.bdlNam => current module's name table
;
;Exit:
; AX - Name table offset of PbCb input string
; 0 is returned for error conditions (out of memory).
; Special: when fDontCreateName != 0, ax = 0 indicates that the
; name wasn't found (and was NOT added to the table).
; DL = tNam.oNam.flags if AX != 0
; PSW flags set via an OR AX,AX on exit
;Uses:
; none
;Exceptions:
; none
;***************************************************************************
cProc ONamOfPbCb,<PUBLIC,NEAR,NODATA>,<DI> ;NOTE: matches entry to ONamOfLn
LocalW pbName ;ptr to string containing symbol
LocalW cbName ;# of bytes in *pbName
LocalW pNamCur
LocalB fGrowTNam ;set if tNam needs to be grown
;before exiting
LocalB fDontReplaceNam ;FALSE if we should replace name in tbl
LocalW lineNum ;line number here, if entry via ONamOfLn
LocalV bdlTmp,<SIZE BDL>
cBegin
mov di,tNam ; not using line # hash table
mov bx,0DFDFH-1 ;upper case mask for NextChar loop
mov dl,31d ;32 hash chains for names (not line #'s)
ONamOf_Common: ;entry from ONamOfLn
DbChk tNam
push si
xor dh,dh
mov [fGrowTNam],dh ;assume that tNam doesn't need to grow
or ch,ch
jns SetReplaceNam ;brif assumption correct
and ch,07FH ;reset high bit
inc dh ;Don't replace the name in the name
; table if entry found, i.e., leave
; case of existing name as-is.
SetReplaceNam:
mov [fDontReplaceNam],dh
DbChk ConStatStructs
mov [pbName],ax ;save input
mov [cbName],cx ;save input
xchg ax,si ;ptr to Name string in SI
push bx ; preserve mask
call FetchPNam ; bx points to desired mrs
GETSEG ES,PTRRS[bx.BDL_seg],,<SIZE,LOAD> ;[10][6][25]
pop bx ; restore mask
DbAssertRel cx,be,CB_MAX_NAMENTRY,CP,<ONamOfPbCb: cbName too large>
DbAssertRel cx,nz,0,CP,<ONamOfPbCb: cbName is 0>
lodsb ;al = 1st byte of symbol to search for
dec cx
jcxz Mask_Hash
dec cx
jcxz Grab_Last ;brif just 2 chars
xor al,[si] ;hash in second char of name
Grab_Last: ;grab last char for use in hash
add si,cx ;point to last char in name
xor al,[si] ;use last char in name for hash too
Mask_Hash:
inc bx
jnz Mask_Hash2 ;brif not a numeric - - (must not shift)
;NOTE: as long as we just use the low
; 5 bits of this for the hash
; index, we don't need to worry
; about upper vs. lower case
; letters.
shr al,1 ;Line numbers tend to end in 0; don't
; use least significant bit to provide
; a more even hash distribution
dec bx
Mask_Hash2:
;at this point, BX = 0FFFF for Line Number, 0DFDF otherwise
xor dh,dh
and ax,dx ;get the 1st char hash value by doing
;doing a MOD 32 (or MOD 8 for line #'s).
;This value is the byte index into
;tNam which is used to obtain the
;ptr to the appropriate symbol chain
shl ax,1 ;convert to word index
add di,ax ;DI = offset to 1st char chain ptr,
;NOTE - this works because tNam
;is a far heap ( ES:0 => tNam )
mov [pNamCur],di ;pass to AddName (if a null chain)
mov dx,ES:[di] ;offset of first symbol in chain
;or 0 if no symbols on chain
NextName:
mov cx,[cbName] ;CX=# of bytes in pbName
NextNameCX: ;this label allows the above 'mov cx'
;to be removed from the inner loop of
;NextName
mov di,dx
or di,di ;test ptr to next symbol
je AddName ;brif end of chain encountered
mov dx,ES:[di] ;dx=ptr to next symbol in the chain
mov [pNamCur],di ;pass to AddName or MapExit
cmp ES:NM_SIZE[di],cl ;are both strings the same size?
jne NextNameCX ;brif different sizes
mov si,[pbName] ;pb of callers name
add di,NM_NAME ;DI = ptr to 1st ASCII char of symbol
NextChar:
lodsb ;AL=next char from pbName
mov ah,ES:[di] ;AH=next char from tNam
inc di ;bump tNam index
and ax,bx ;BX contains 0DFDFH, so this converts
;AH & AL to upper case by resetting
;their respective bit 5's. This
;mapping works because there are
;no control or special chars in the
;symbol names.
cmp ah,al ;is pbName[SI]=tNam[DI]
jne NextName ;brif chars not the same
loop NextChar ;loop till mismatch or all chars tested
;
;We found a case insensitive match - if the names are exactly the same, then
;just quit (typical case?), otherwise, tell the UI that it needs to redraw
;the debug screen, and replace the name in the table
cmp [fDontReplaceNam],FALSE ;want to replace the name in the table?
jz DoReplaceName ; brif so
MapExit1:
jmp MapExit ; nope - just exit
DoReplaceName:
mov di,[pNamCur] ;addr of symbol record that matched
mov si,[pbName] ;pb of symbol to add
mov cx,[cbName] ;# of bytes in pbName
add di,NM_NAME ;offset to 1st byte of new entry name
repz cmpsb ;are names exactly the same?
jz MapExit1 ; brif so - exit
push es ;preserve across call
call DrawDebugScrFar ;inform UI
pop es
mov di,[pNamCur] ;addr of symbol record that matched
jmp short CopyString ;copy DS:[pbName] to ES:[DI+NM_NAME]
;
; Add pbName to the end of the current chain
AddName:
xor ax,ax ;0 for initializing new fields
mov [fGrowTNam],TRUE ;tNam needs to grow
;
; make the last entry point to the next empty symbol
;
mov di,ES:[cbUsed] ;# of allocated bytes in tNam
;this is also the addr of the next
;available byte since cbLogical is
;greater than cbUsed
mov ES:NM_NEXT[di],ax ;NULL ptr for new record
inc bx ;is this name for a Line Number?
jnz Not_Ln ; brif not
mov al,NM_fLineNum ;set flag to recall that this is a Line#
Not_Ln:
mov ES:[di+NM_FLAGS],al ;initialize flags to OFF state
;
; copy the pb string to [ES:DI.name]
CopyString:
mov si,[pbName] ;pb of symbol to add
mov cx,[cbName] ;# of bytes in pbName
mov ES:NM_SIZE[di],cl ;update length field of symbol
;NOTE - this may be redundant
add di,NM_NAME ;offset to 1st byte of new entry name
rep movsb ;copy from DS:pbName[SI] to ES:tNam[DI]
cmp [fGrowTNam],FALSE ;do we need to grow tNam
je MapExit ;brif symbol wasn't added - don't need
;to grow tNam
;
; Make sure there will be enough room to add another symbol the next time thru.
; TNam can now be safely grown since the string has been copied and heap
; movement is no longer a problem.
;
mov cx,[oRsNam] ;[10]
jcxz MrsCur_Okay ; brif want to grow bdl in mrsCur
; We want to grow the bdlNam for the global mrs, but it's not
; active. It must be active because (1) cannot safely grow a bdl
; when it's in a local heap table, and (2) we need to know where
; the owner of the bdl is in case of heap movement, to refresh es.
; Therefore, we active and then deactivate the global mrs.
; NOTE: This assumes that the only reason pMrsNam is non-zero is
; for global mrs support.
; Note: we save both oPrsCur AND oMrsCur here instead of oRsCur
; to protect against the special case where a declared/ref'd
; but not defined prs is active here ... in this special case,
; RsActivate of oRsCur would leave the global mrs active ...
push [grs.GRS_oPrsCur] ; save for later restore
push [grs.GRS_oMrsCur] ; save for later restore
PUSHI ax,OMRS_GLOBAL ;[23] oMrs of global mrs
call MrsActivateCP ; activate the global mrs
MrsCur_Okay:
mov bx,dataOFFSET mrsCur.MRS_bdlNam ; pointer to tNam bdl
mov ax,CB_MAX_NAMENTRY+NM_NAME+NM_NAME
; max # of bytes needed to add
;the next symbol plus the
;overhead needed by the
;current symbol.
add ax,[cbName] ;plus the _NAME field bytes used by
;the current symbol
mov di,[pNamCur] ;addr of last searched name entry
push bx ; pass pbdlNam to BdlCheckFree
push ax ;pass byte count to BdlCheckFree
call BdlCheckFree ;make sure there is enough room in tNam
;to add another symbol
xchg ax,si ; save return code across poss. call
mov cx,[oRsNam] ;[10]
jcxz MrsCur_Okay1 ; brif mrsCur is to be left alone
; The oRs of the context that was active on input is on the top
; of the stack. Activate this again, and then refresh pMrsNam in
; case the mrs table moved and pMrsNam will be used again.
mov [oRsNam],0 ; reset so global mrs access in
; MrsActivateCP will be correct
call MrsActivateCP ; reactivate input oMrsCur
call PrsActivateCP ; reactivate input oMrsCur
call Use_GMrs
MrsCur_Okay1:
sub ax,ax ; in case of error
or si,si ; BdlCheckFree return code
je ONamOfPbCb_Exit ;brif not enough memory - the current
;name isn't added to tNam - even
;though the _NAME field has been
;updated.
mov si,[cbName] ;# of bytes in new symbol
add si,NM_NAME ;compensate for header bytes
;SI = # of bytes in new entry
call FetchPNam ; bx points to desired mrs
mov dx,PTRRS[bx.BDL_cbLogical] ;[10] # of bytes in Name Table
add dx,si ; + padding for next symbol
js ONamOfPbCb_Exit ;brif table has grown > 32k
; see module header for reason(s) for
; this restriction
mov PTRRS[bx.BDL_cbLogical],dx ;[10]
GETSEG ES,PTRRS[bx.BDL_seg],,<SIZE,LOAD> ;[14][10][6]
; may have been changed by the
; call to BdlCheckFree
;make the last entry point to the
; next empty symbol
mov ax,ES:cbUsed ;# of tNam bytes already used
;this is also the addr of the next
;available byte since cbLogical is
;greater than cbUsed
mov ES:[di],ax ;make the last entry point to new entry
mov di,ax ;return new oNam to caller
add ax,si ;cbUsed + size of new entry
mov ES:cbUsed,ax ;# of bytes used by the Name Table
mov [pNamCur],di ;return new oNam to caller
MapExit:
mov bx,[pNamCur] ;return name offset to caller in AX
mov dl,ES:NM_FLAGS[bx] ;get the flag byte
xchg ax,bx
ONamOfPbCb_Exit:
pop si
or ax,ax ;set flags for callers
cEnd
;***
;TNamInit TNamInit()
;Purpose:
; To initialize the Name Table structure and any other data used by
; the Name Table Manager. A zero is returned in AX if there was not
; enough memory.
;Entry:
; sbToUse - 0 means use any sb for this table. If non-zero, then this
; sb value is to be used.
; mrsCur.bdlNam = current module's name table
;Exit:
; AX = 0 if not enough memory was available
;Uses:
; none
;Exceptions:
; none
;***************************************************************************
cProc TNamInit,<PUBLIC,NEAR,NODATA>,<DI>
parmW sbToUse
cBegin
mov ax,dataOFFSET mrsCur.MRS_bdlNam ; ptr to tNam bdl
push ax ; parm to BdlAlloc
cCall BdlFree,<ax> ; in case name table is an owner
mov ax,NM_INIT_TABLE_SZ ;# of bytes to allocate
push ax ;pass low word of cb to BdlAlloc
PUSHBDL_TYPE pgtypEBNameTable,ax ; pass sb type for EB version
mov cx,[sbToUse]
jcxz Use_Any_Sb
push cx
call BdlAllocSb
jmp short TNamInit_Cont
Use_Any_Sb:
call BdlAlloc ;allocate a large far heap for NamTab
TNamInit_Cont:
or ax,ax ;check return code
je TNIExit ;brif heap wasn't allocated
;
;we now own a far heap entry - initialize it
;
GETSEG ES,[mrsCur.MRS_bdlNam_seg],,<SIZE,LOAD> ;[6]
mov cx,mrsCur.MRS_bdlNam_cPhysical ;# of paragraphs in Name Table
shl cx,1 ;convert cPara to cBytes
shl cx,1 ; (under DOS 5 this already is cBytes)
shl cx,1
shl cx,1
mov di,tNam ;di=base addr of tNam
;NOTE - tNam is a far heap
sub cx,di ; zero-fill all but initial bytes
sub ax,ax ;AX=0
REP STOSB ;Initialize the Name table
mov ax,oNamFirst ;offset to 1st usable entry
mov ES:cbUsed,ax ;# of bytes currently being used
;by tNam
add ax,NM_NAME+CB_MAX_NAMENTRY
; # of bytes currently being used
;by tNam + enough padding to add
;another symbol
mov mrsCur.MRS_bdlNam_cbLogical,ax ;total size of tNam
TNIExit:
cEnd
;***
;CopyONamPb cbW = CopyONamPb
;Purpose:
; To copy the ASCII chars in a name table entry to the callers buffer.
; The # of ASCII characters copied is returned.
;Assumptions:
; pbW contains room for at least CB_MAX_NAMENTRY chars
;Register conventions:
; DS - tNam segment
; ES - pb segment
; SI - tNam pointer
; DI - pb pointer
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -