⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nhlhcore.asm

📁 [随书类]Dos6.0源代码
💻 ASM
📖 第 1 页 / 共 3 页
字号:
	JNZ	ADJLHP_ALL_FLDS ;if adjustment, then adust fielded strings
	MOV	[SI].LHTYPE,LOW LH_FREE ;mark the deallocated block free
	CALL	B$LHDALCALLFLD	; otherwise deallocate all fielded strings
	JMP	SHORT ADJLHP_QUIT ;jump to return to caller

;	Entry contains fielded strings - adjust pointers into field buffer

ADJLHP_ALL_FLDS:
	MOV	CX,[SI].LHPLEN	;get size of string entry for fielded strs
	SHR	CX,1		;compute number of fielded strings
	PUSH	SI		;preserve heap pointer
ADJ_FLD_LOOP:
	MOV	SI,[BX] 	;get pointer to field variable
	ADD	[SI+2],AX	;adjust pointer into field buffer
	INC	BX		;move to next field variable
	INC	BX
	LOOP	ADJ_FLD_LOOP	;loop until all ptrs to field buffer have
				;been adjusted
	POP	SI		;recover heap pointer
ADJLHP_EXIT:
	JMP	SHORT ADJLHP_QUIT ;jump to return to caller

;	If entry is not ARRAY, then return.

ADJLHP_NOT_FILE:
	CMP	[SI].LHTYPE,LOW LH_ARRAY ;test if entry is ARRAY
	JNE	ADJLHP_INTERP	;if not, consider interp. entries (if any)

;	Entry is ARRAY, first clear/adjust the array descriptor pointer.

	MOV	BX,[SI].LHBAKP	;get offset of array descriptor
	OR	AX,AX		;test if array is being deallocated
	JNZ	ADJLHP_ADJUST	;if just being adjusted, then jump
	MOV	[BX].AD_fhd.FHD_hData,AX ;deallocated - clear the descriptor
	MOV	[SI].LHBAKP,AX	;also clear the heap backpointer
	MOV	[SI].LHTYPE,LOW LH_FREE ;mark the deallocated block free
ADJLHP_ADJUST:

;	Next, get pointer to start of array data and deallocate/adjust
;	the backpointers of all nonnull strings in the array.

	MOV	CX,[SI].LHLEN	;get length of heap entry (hdr+data+backlen)
	MOV	BX,SI		;get copy of heap entry pointer
	SUB	BX,CX		;point to next heap entry
	ADD	BX,3		;move past backlength to array start
	SUB	CX,LH_STD_HDR_LEN+2 ;data length less header and backlength
	SHR	CX,1		;data length in words...
	SHR	CX,1		;length in doublewords (number of descs)

;	For each nonnull descriptor, deallocate/adjust the string data.
; Process null strings through B$STADJ, fielded ones must be adjusted.

ADJLHP_LOOP:
;	CMP	WORD PTR [BX],0 ;test if string is nonnull
;	JZ	ADJLHP_NEXT	;if so, then skip this entry
	CALL	B$STADJ	;deallocate/adjust the string at desc [BX]
ADJLHP_NEXT:
	ADD	BX,4		;point to next descriptor
	LOOP	ADJLHP_LOOP	;loop to process the next one

ADJLHP_INTERP:

	OR	AX,AX
	JZ	ADJLHP_QUIT	;brif deallocation - the below is for adjustment
	CALL	B$LH_I_ADJ	;[ln] adjust backptrs to any owners in this entry

ADJLHP_DONE:
	;NOTE: important to update the owner LAST, after interpreter call
	;	back work is done.
	MOV	BX,[SI].LHBAKP	;get pointer to owner
	ADD	[BX],AX 	;add adjustment to owner pointer
	CMP	[SI].LHTYPE,LOW LH_ARRAY; test if entry is ARRAY
	JNE	ADJLHP_QUIT		; jump if not
	ADD	[BX].AD_oAdjusted,AX	; else update adjusted pointer

ADJLHP_QUIT:
	POP	CX		;restore registers...
	POP	BX
	RET			;return to caller
B$LHADJ  ENDP			
assumes	DS,DGROUP		
assumes	ES,NOTHING		


;***
; B$LHDALCALLFLD - deallocate all fielded strings for heap entry
; Purpose:
;	To deallocate all fielded strings associated with the heap
;	entry pointed by SI.  The heap backpointer string is also
;	deallocated.
;
; Inputs:
;	SI = pointer to heap entry
; Outputs:
;	None.
; Modifies:
;	None.
; Exceptions:
;	None.
;****

B$LHDALCALLFLD:		
	ASSERT_NOT_VARHEAP NH_TEXT 
	PUSH	AX		;save registers...
	PUSH	BX
	PUSH	CX
	PUSH	DI
	XOR	AX,AX		;clear AX to zero
	MOV	BX,AX		;same for BX...
	MOV	CX,AX		;and CX
	XCHG	CX,[SI].LHPLEN	;swap bkptr str len and 0
	XCHG	BX,[SI].LHPOFF	;swap bkptr str off and 0
	INC	CX		;add one for backpointer value
	MOV	[BX-2],CX	;free string by setting backpointer value
	SHR	CX,1		;number of words to process
DALCALLFLD_LOOP:
	MOV	DI,[BX] 	;get next word from string
	MOV	[DI],AX 	;clear descr length
	MOV	[DI+2],AX	;clear descr offset
	ADD	BX,2		;point to next descriptor in string
	LOOP	DALCALLFLD_LOOP ;if not done, then loop
	POP	DI		;restore registers...
	POP	CX
	POP	BX
	POP	AX
	RET			;return to caller


;***
; B$LHFLDDESCADJ - delete/adjust descriptor in field backpointer string.
; Purpose:
;	Search through the local heap FILE entries for the descriptor
;	address specified in BX.  If AX=0, then remove it from the
;	field backpointer string.  If AX<>0, then just adjust the
;	backpointer string element by adding AX to it.
;
; Inputs:
;	AX = adjustment factor
;	     AX=0 - delete descriptor BX from backpointer string.
;	     AX<>0 - adjust descriptor BX in backpointer string by AX.
;	BX = address of descriptor to be deleted/adjusted.
;	DS = segment that heap is in
;	ES = segment that state vars are in
; Outputs:
;	None.
; Modifies:
;	SI.
; Exceptions:
;	B$ERR_SSC if descriptor offset not found.
;****

B$LHFLDDESCADJ:
assumes	ES,DGROUP		
assumes	DS,NOTHING		

	ASSERT_NOT_VARHEAP NH_TEXT 

	PUSH	AX		;save registers...
	PUSH	BX
	PUSH	CX
	PUSH	DX
	PUSH	DI

	XCHG	DX,AX		; [DX] = adjustment factor
	XCHG	AX,BX		; [AX] = object of searches
	XOR	BX,BX		;start at beginning of heap
FLDDESCADJ_NEXT:
	MOV	SI,BX		;put current FDB point in for test
	CALL	NXTFIL_ES	;get next FILE data pointer in SI
	JZ	FLDDESCADJ_ERROR ;if no more entries, then done

	MOV	BX,SI		;save current FDB point for next time
	CALL	B$LH_PTR_FROM_DATA ;get heap entry pointer in SI

;	Heap entry is for a file.  Determine if a backpointer string
;	is defined.  If so, then scan string for descriptor value in AX.

	MOV	CX,[SI].LHPLEN	;get length of string
	JCXZ	FLDDESCADJ_NEXT ;if null string, then try next entry
	SHR	CX,1		;make it in words
	MOV	DI,[SI].LHPOFF	;get offset of the string
	PUSH	ES		;make sure that we use the proper
	PUSH	DS		;segment in case that
	POP	ES		;we are in the middle of unwinding a CHAIN
	REPNE	SCASW		;scan for word in AX
	POP	ES		;recover correct ES = BASIC DS
	JNZ	FLDDESCADJ_NEXT ;if not there, try next

;	Word found in string.  DI is pointing just after the word
;	while CX contains the number of words in the string AFTER
;	the one searched.  If modifying (DX<>0), just add the adjustment
;	factor to the word.

	ADD	[DI-2],DX	;assume adjustment is made (deleted otherwise)
	OR	DX,DX		;test if adjustment really wanted
	JNZ	FLDDESCADJ_DONE ;if so, then jump to return now

;	If deleting (DX=0), start at DI and move CX words left by two
;	and put a null free string header where the last word of the
;	string was.

	SUB	WORD PTR [SI].LHPLEN,2 ;string size is less by 2
	JZ	FLDDESCADJ_CLR	;jump if string is now empty
	MOV	SI,DI		;SI points to byte after
	DEC	DI		;point DI to...
	DEC	DI		;the word before (AX value)
	PUSH	ES		;make sure that we use the proper
	PUSH	DS		;segment in case that
	POP	ES		;we are in the middle of unwinding a CHAIN
	REP	MOVSW		;move the string left 2
	POP	ES		;recover correct ES = BASIC DS
	MOV	WORD PTR [DI],1 ;null string free header
	JMP	SHORT FLDDESCADJ_DONE ;done, jump to finish
FLDDESCADJ_CLR:
	XOR	DI,DI		;clear register
	XCHG	DI,[SI].LHPOFF	;clear descr offset, get it
	MOV	WORD PTR [DI-2],3 ;set ptr to empty string
FLDDESCADJ_DONE:
	POP	DI		;restore registers...
	POP	DX
	POP	CX
	POP	BX
	POP	AX
	RET			;return to caller

FLDDESCADJ_ERROR:
	JMP	B$ERR_SSC	; report string space corruption
assumes	DS,DGROUP		
assumes	ES,NOTHING		

;***
; B$LHNXTFIL, NXTFIL_ES - return FDB pointer of next file in heap after [SI]
; Purpose:
;	To return a pointer to the next FDB in the heap.  The
;	local heap is searched from the last FDB specified in SI
;	(or the first if SI=0).
;
; Inputs:
;	SI = pointer to FDB to start search from (0 if first FDB
;	     pointer is to be returned).
; Outputs:
;	SI = pointer to next FDB after the one specified on routine
;	     entry (0 if no more FDB's in the heap).
;	ZF = clear if FDB returned
;	     set if none returned
; Modifies:
;	None.
; Exceptions:
;	None.
;****
NXTFIL_ES:			;Assumes ES already set up
	PUSH	ES		
	JMP	SHORT NXTFIL_COMMON 

B$LHNXTFIL:			
	PUSH	ES		
	PUSH	DS		
	POP	ES		;set ES = DS

NXTFIL_COMMON:			;common entry
	ASSERT_NOT_VARHEAP NH_TEXT 
assumes	ES,DGROUP		
assumes	DS,NOTHING		
	OR	SI,SI		;test if first file is to be searched
	JNZ	NXTFIL_NEXT	;if so, then branch
	MOV	SI,ES:[b$HEAP_FIRST] ;initialize to start of local heap
	ADD	SI,3		;adjust to avoid extra jump
NXTFIL_NEXT:
	SUB	SI,3		;move from FDB over backlength to next entry
NXTFIL_LOOP:
	CMP	[SI].LHTYPE,LOW LH_END ;test if last entry in heap
	JE	NXTFIL_END	;if so, then jump
	CMP	[SI].LHTYPE,LOW LH_FILE ;test if entry is file
	JE	NXTFIL_FILE	;if so, then jump
	SUB	SI,[SI].LHLEN	;point to next heap entry
	JMP	SHORT NXTFIL_LOOP ;and continue the search
NXTFIL_FILE:
	SUB	SI,[SI].LHLEN	;point to previous entry
	ADD	SI,3		;move over backlength to entry FDB
assumes	ES,NOTHING		
	POP	ES		
	RET			;return to caller (ZF clear)
NXTFIL_END:
	XOR	SI,SI		;clear to show no more files
	POP	ES		
	RET			;return to caller (ZF set)

;***
;B$LH_PTR_FROM_DATA - get heap entry pointer from data pointer
;LH_PTR_FROM_BLEN - get heap entry pointer from backlength pointer
;B$LH_PTR_CHECK     - check heap entry referenced by its pointer
;
;Purpose:
; From the pointer given return the heap entry data pointer. Also check the
; heap entry by matching its length and backlength values and confirming that
; the length is nonzero.
;
;Inputs:
; SI = specified pointer
;
;Outputs:
;
; SI = heap entry header pointer
;
;Modifies:
; None.
;
;Exceptions:
; If heap entry is inconsistent, jump to B$ERR_SSC.
;****

B$LH_PTR_FROM_DATA:
	SUB	SI,2		;now point to entry backlength
LH_PTR_FROM_BLEN:
	ADD	SI,[SI] 	;point to one past header entry
	DEC	SI		;point to header entry
B$LH_PTR_CHECK:
	PUSH	AX		;save registers...
	PUSH	DI
	MOV	AX,[SI].LHLEN	;get length of heap entry
	MOV	DI,SI		;compute offset of entry backlength...
	SUB	DI,AX		;by moving the pointer to before backlength
	CMP	[DI+1],AX	;compare entry length and backlength
	JNE	LH_PTR_ERROR	;if not equal, then report error
	OR	AX,AX		;test for illegal zero value
	JZ	LH_PTR_ERROR	;if so, then jump
	POP	DI		;restore registers...
	POP	AX
	RET			;return to caller

LH_PTR_ERROR:
	PUSH	ES		;force DS = basic dgroup in case
	POP	DS		;we are unwinding chain
assumes	DS,DGROUP		
	DbHalt NH_TEXT,<B$LH_PTR_CHECK found inconsistent heap entry>
	JMP	B$ERR_SSC	;note heap is inconsistent if ID_RELEASE version

;***
; B$LHSetFree - set free heap entry pointer
; Purpose:
;	Determines if the current free heap entry is both the last
;	heap entry and unallocated.  If so, its current value is
;	returned in DI.  Otherwise, the free heap entry pointer
;	[b$HEAP_FREE] is set to the heap space end and its value returned
;	in DI.
;
; Inputs:
;	None.
; Outputs:
;	DI = pointer to free heap entry [b$HEAP_FREE].
; Modifies:
;	AX.
; Exceptions:
;	None.
;****
B$LHSetFree	PROC	NEAR
	MOV	DI,[b$HEAP_FREE] ;point to free heap entry
	CMP	[DI].LHTYPE,LOW LH_FREE ;test if entry unallocated
	JNE	LH_SET_END	;if allocated, then jump
	MOV	AX,DI		;get pointer to free entry
	SUB	AX,[DI].LHLEN	;point to entry after free one
	CMP	AX,[b$HEAP_END] ;test if free entry was last in space
	JE	LH_SET_RETURN	;if so, jump leaving pointer unchanged
LH_SET_END:
	MOV	DI,[b$HEAP_END] ;get pointer to heap end
	CMP	DI,[b$HEAP_FIRST] ; Empty heap?
	JZ	LH_SET_FREE	; then don't try anything fancy
	MOV	AX,DI		; [AX] = pointer to end entry
	ADD	AX,[DI+1]	; [AX] = pointer to entry before end
	XCHG	AX,DI		; [AX] = ptr to end, [DI] = entry before
	CMP	[DI].LHTYPE,LOW LH_FREE ; test if entry after unallocated
	JZ	LH_SET_FREE	; if so, that's the free entry
	XCHG	AX,DI		; else use end entry
LH_SET_FREE:
	MOV	[b$HEAP_FREE],DI ;and set the free pointer to it
LH_SET_RETURN:
	RET			;return with DI pointing to free entry
B$LHSetFree	ENDP

	SUBTTL	B$NHINIT - Initialize dynamic space
	PAGE
;***
; B$NHINIT - Initialize dynamic space
; Purpose:
;	Initialize the necessary pointers and structures for string and
;	local heap space.
; Inputs:
;	AX = first word of dynamic space.
;	CX = last word of dynamic space.
; Outputs:
;	None.
; Modifies:
;	None.
; Exceptions:
;	None.
;****
cProc	B$NHINIT,<PUBLIC,NEAR>,<AX,BX,CX,SI,DI>	
cBegin					

	MOV	SI,CX			;get last word of dynamic space
	INC	SI			;point to last byte of space
	MOV	[b$HEAP_FIRST],SI	;the local heap starts here...
	MOV	[b$HEAP_FREE],SI	;has its free entry here...
	MOV	[b$HEAP_END],SI 	;and ends here
	MOV	[SI].LHTYPE,LOW LH_END	;set the heap entry type

	ADD	AX,LH_STD_HDR_LEN	; dyn space starts after var heap
	MOV	[b$NH_first],AX	
	MOV	BX,AX			
	DEC	BX			; point to last byte of var heap
	MOV	[b$HEAP_FIRST_SWAP],BX	; the variable heap starts here...
	MOV	[b$HEAP_FREE_SWAP],BX	; has its free entry here...
	MOV	[b$HEAP_END_SWAP],BX	; and ends here
	MOV	[BX].LHTYPE,LOW LH_END	; set heap entry type
	;Set up pointers to routine to be called when B$ILHALC needs to
	;  grow the appropriate heap
	MOV	[P_HEAP_GROW_SWAP],NH_TEXTOFFSET B$VAR_ALC_GROW ;[ln]
	MOV	[b$P_HEAP_GROW],NH_TEXTOFFSET LH_ALC_GROW	;[ln]
	SUB	SI,LH_STD_HDR_LEN+1	;point to even address before entry
	CMP	b$Clearing,0		;are we doing a CLEAR statement?
	JZ	NotClearing		;no, go initialize string space
	CALL	B$SSClean		; clean out entries, so we don't
	JMP	SHORT InitExit		; bash function keys
NotClearing:				
	CALL	B$STINIT		;initialize string space
InitExit:				

cEnd					

sEnd	NH_TEXT
	END

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -