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

📄 strstack.asm

📁 random.zip 随机数产生器的汇编源代码 cmdsrc.zip 一个文本编辑器的汇编源代码
💻 ASM
📖 第 1 页 / 共 2 页
字号:
; STRSTACK.ASM
; (c) 1989, 1990 Ashok P. Nadkarni
;
; Functions to implement the string stack object for CMDEDIT. Small Model only.
;

	INCLUDE common.inc
	INCLUDE general.inc
STRSTACK_ASM	EQU	1


CSEG	SEGMENT PARA PUBLIC 'CODE'
CSEG	ENDS

DGROUP	GROUP	CSEG

	INCLUDE	buffers.inc

CSEG	SEGMENT PARA PUBLIC 'CODE'

	ASSUME	CS:DGROUP, DS:DGROUP, SS:DGROUP, ES:DGROUP

	EXTRN	stre_cmp:PROC

;+
; FUNCTION : strstk_init
;
;	Initializes a $STRING_STACK descriptor. Note that buffer will contain
;	overhead as well as the actual data itself.
;
; Parameters:
;	BX := address of descriptor
;	AX := address of buffer
;	CX := buffer size
;
; Returns:
;	AX = 0 if success
;	else -1
;
; Register CX destroyed.
;-

strstk_init proc near

	cmp	cx,2		;Need at least 2 bytes in buffer (sentinel)
	jb	@strstk_init_90	;
	cmp	cx,32767	; and LESS than 32767 (Need to represent
	jnc	@strstk_init_90 ; + and - differences between first location
				; and first location beyond buffer in 16 bits)
	mov	[bx].low_end,ax	;starting address
	add	cx,ax		;Location after last addressable byte of buffer
				;Various functions assume byte beyond last
				;buffer location is addressable without
				;segment wraparound.
	jc	@strstk_init_90	;Segment wraparound.
	dec	cx		;CX->Last byte in buffer
	mov	[bx].high_end,cx
	call	near ptr strstk_reset
	xor	ax,ax		;success
	jmp	short @strstk_init_99
@strstk_init_90:		 ;Buffer too small or 
	mov	ax,-1		 ; overflow (add ax,cx instruction)
@strstk_init_99:
	ret

strstk_init endp



;+
; FUNCTION : strstk_reset
;
;	Resets a specified stack to its initial state. The sentinel at the
;	bottom of the stack is assumed to be already there.
;
; Parameters :
;	BX := address of buffer descriptor
;
; Returns :
;	Nothing.
;
; Registers destroyed:
;	AX
;-
strstk_reset proc near
	mov	ax,[bx].low_end
	xchg	ax,bx
	mov	word ptr [bx],0	;header & trailer for sentinel null string
	xchg	ax,bx
	inc	ax		;
	mov	[bx].top,ax	;Stack top (sentinel null)
	mov	[bx].cur,ax	;Current string (sentinel null)
	mov	[bx].savecur,ax
	mov	ax,[bx].high_end		;AX->last byte of buffer
	inc	ax				;AX->first byte beyond buffer
	mov	[bx].topmark,ax			;No markers
	ret
strstk_reset endp


;+
; FUNCTION: strstk_save_cur
;
;	This function saves the cur pointer in the cursave field of the
;	descriptor structure. It can then be restored with the
;	strstk_restore_cur call. It is the caller's responsibility to
;	ensure that the stack does not change in the meanwhile in such a
;	way as to invalidate the pointer into it. Generally do not do
;	anything except move the cur pointer around to access different
;	strings.
;
; Parameters :
;	BX := address of buffer descriptor
;
; Returns :
;	Nothing.
;
; Registers destroyed:
;	AX
strstk_save_cur proc near
	mov	ax,[bx].cur
	mov	[bx].savecur,ax
	ret
strstk_save_cur endp

;+
; FUNCTION: strstk_restore_cur
;
;	This function restores the cur pointer from the cursave field of the
;	descriptor structure where it was stored through the
;	strstk_save_cur call. It is the caller's responsibility to
;	ensure that the stack does not change in the meanwhile in such a
;	way as to invalidate the pointer into it. Generally do not do
;	anything except move the cur pointer around to access different
;	strings. Also, make sure you do a strstk_save_cur before every
;	strstk_restore_cur.
;
; Parameters :
;	BX := address of buffer descriptor
;
; Returns :
;	Nothing.
;
; Registers destroyed:
;	AX
strstk_restore_cur proc near
	mov	ax,[bx].savecur
	mov	[bx].cur,ax
	ret
strstk_restore_cur endp



;+
; FUNCTION : strstk_space
;
;	Returns the available space in the buffer. This is 2 less than the
;	actual number of bytes remaining since we need space for a header
;	and a trailer for at least one string.
;
; Parameters:
;	BX := address of buffer descriptor
;
; Returns:
;	CF :=	1 if no space in stack even for a header or trailer
;		0 otherwise
;	AX :=	Available space (length of max string that can be fitted)
;		if CF = 0, if CF = 1, AX is indeterminate
;-
strstk_space proc near
	mov	ax,[bx].topmark	;Points BEYOND last usable byte
	sub	ax,[bx].top	;actual space in buffer + 1
				;Need to deduct 1+2(for header/trailer)
	sub	ax,3		;Don't use multiple 'dec ax' here
				; since it does not set CF.
	ret
strstk_space endp




;+
; FUNCTION : strstk_settop
;
;	Sets the current string pointer to point to the newest (top
;	of stack) string.
;
; Parameters:
;	BX :=	address of buffer descriptor 
;
; Returns:
;	Nothing.
;
; Register AX destroyed.
;-
strstk_settop proc near
	mov	ax,[bx].top
	mov	[bx].cur,ax
	ret
strstk_settop endp



;+
; FUNCTION : strstk_setbot
;
;	Sets the current string pointer to point to the oldest (bottom
;	of stack) string. If the stack is not empty, the null string at
;	the bottom is ignored.
;
; Parameters:
;	BX :=	address of buffer descriptor 
;
; Returns:
;	Nothing.
;
; Registers AX,DX destroyed.
;-
strstk_setbot proc near
	mov	ax,[bx].low_end
	inc	ax
	cmp	ax,[bx].top	;Is stack empty ?
	je	@strstk_setbot_99 ;Yes
	inc	ax		;Point ax to header of oldest string
	xchg	ax,si		;Store in SI
	mov	dl,[si]		;get length of string
	xor	dh,dh
	add	si,dx		;Point SI to last byte in string
	inc	si		;Point SI at trailer
	xchg	ax,si		;Restore SI and set AX to point to trailer
@strstk_setbot_99:
	mov	[bx].cur,ax	;Set current pointer
	ret
strstk_setbot endp



;+
; FUNCTION : strstk_kill
;
;	Deletes the "current" string from the stack. All strings above it
;	are moved up. "current" string is updated to point to the string
;	above the deleted string unless the topmost string was deleted
;	in which case it is set to top of stack. 
;
;	Any markers pointing at the deleted string are updated to
;	point to the new "current" string. Any markers pointing above
;	the deleted string updated to keep pointing to their
;	respective strings even after the latter are moved down.
;	Naturally, the marks below the deleted string do not change.
;
; Parameters:
;	BX :=	address of buffer descriptor
;
; Returns:
;	Nothing
;
; Registers AX,CX,DX destroyed
;-
strstk_kill proc near
	@save	si,di

	mov	si,[bx].cur
	mov	ax,[bx].low_end	;When current points to the sentinel string,
	inc	ax		; exit without deleting it
	cmp	ax,si		;Sentinel current ?
	je	@strstk_kill_99 ;Yes, exit

	mov	cx,[bx].top	;topmost occupied location
	mov	dx,cx		;remember it
	sub	cx,si		;Num bytes to be moved into vacated positions

	xor	ax,ax
	mov	di,si		;di will be used to point to the header of
				; the deleted string.
	lodsb			;Get the string length into AX.
				;At the same time SI now points to header
				;of the string following the condemned string.
	inc	ax
	sub	di,ax		;di now points to the condemned string header.
	inc	ax
	push	ax		;Remember how many bytes are to be removed
	sub	dx,ax		;Top of stack is now (length of string + 2)
	mov	[bx].top,dx	; below the original top

	jcxz	@strstk_kill_50 ;If # bytes to be moved is 0, then the
				;deleted string was at the top of the stack.
	push	di		;remember header position
	rep	movsb		;Copy CX bytes down into vacated positions
	pop	si		;Header position of new "current" string
				; (same location as header of old current)
	lodsb			;SI points to first byte of string
	xor	ah,ah		; and AL = length of new current string.
	add	ax,si		;AX now points to trailer of new "current"
	jmp	short @strstk_kill_90 ;exit

@strstk_kill_50:		;Deleted element was top of stack
	xchg	ax,dx		;ax = top, we want cur to be == top

@strstk_kill_90:
	xchg	ax,[bx].cur	;cur = top, ax = old current
	pop	cx		;Restore the removed byte count
				; (counterpart of the 'push ax' above)
	IF	WANT_MARKERS
	call	strstk_update_marks ;Update marks for strings that were moved
				    ;  ax == old cur, cx == displacement
	ENDIF
@strstk_kill_99:
	@restore
	ret
strstk_kill endp




;+
; FUNCTION : strstk_push
;
;	Pushes a string onto the top of the stack. If the force flag parameter
;	is set to any value other than 0, one or more strings at the bottom
;	of the stack are deleted to make room fir the new string. If the force
;	flag is 0, then an error is returned if there is not sufficient room
;	in the stack. An error is also returned if the string is bigger than
;	stack size. The stack is left unaltered for both error conditions.
;
; Parameters:
;	BX :=	address of buffer stack descriptor
;	AL :=	Length of string
;	CX :=	force flag
;	DX :=	address of string to be pushed
;
; Returns:
;	Carry flag is set if error (not enough stack space), else it is clear.
;
; Registers AX,CX,DX destroyed.
;-
strstk_push proc near
	@save	si,di
	xor	ah,ah		;Clear high byte of length.
	mov	si,dx		;SI := source string
	push	ax		;save length
	jcxz	@strstk_push_10	;Jump if force flag is 0
	call	strstk_makespace ;Make sure enough space, else make space
	pop	cx		;restore length
	jc	@strstk_push_99	;Error return by strstk_makespace
	jmp	short @strstk_push_20 ;Everything OK, go push string
@strstk_push_10:
	call	near ptr strstk_space	;Find out how much space is left
	pop	cx		;Restore string length
	jb	@strstk_push_99		;Not even enough for header/trailer,
;					 error  return
	cmp	ax,cx		;Enough space on stack ?
	jb	@strstk_push_99	;Nope, error return
@strstk_push_20:		;OK, copy string onto stack
	mov	di,[bx].top	;DI := last occupied location on stack
	inc	di		;DI := address of header for new string
	mov	ax,cx		;Get length into AL
	stosb			;Store length in header
 	rep	movsb		;Copy string
	mov	[bx].top,di	;New top of stack is trailer of topmost string
	mov	[bx].cur,di	;Ditto for current string
	stosb			;Store length in trailer
	clc			;Success return
@strstk_push_99:
	@restore
	ret
strstk_push endp


;+
; FUNCTION : strstk_fwd_match
;
;	Searches towards the top of the stack, starting from the string
;	above the current string looking for a string that has the specified
;	pattern as a prefix.  If the pattern length is 0, then the match is
;	universal and the new current string is simply the one immediately
;	above the current one.  The function can thus be used to move the
;	cur pointer up the stack one string at a time. If the current
;	string is at the top of the stack, the cur pointer remains
;	unchanged.
;
; Parameters:
;	BX :=	address of buffer stack descriptor
;	AX :=	Address of pattern
;	CX :=	Length of pattern 
; Returns:
;	CF  = 1 if no match or if at top of stack
;	    = 0 if success
;
; Registers AX,CX destroyed.
;-
strstk_fwd_match proc near
	@save	si,di
	mov	si,[bx].cur	;SI:=current ptr
	mov	di,AX		;Pattern address
	
@strstk_fwd_match_10:
	cmp	si,[bx].top	;Are we at top of stack ?
	je	@strstk_fwd_match_90 ;Yes, error exit
	inc	si		;SI:=point to next header
	lodsb
	xor	ah,ah		;AX := string length
	cmp	ax,cx		;Is the pattern longer than string ?
	jnb	@strstk_fwd_match_70 ;If not go try a match
				;Yes, then try next string
	add	si,ax		;Point to trailer
	jmp	short @strstk_fwd_match_10 ;and loop back	
@strstk_fwd_match_70:		;OK, see if pattern is the string prefix
	push	cx		;Remember pattern length
	push	ax		;Remember string length
	call	near ptr stre_cmp ;Check if pattern is a prefix
	pop	ax		;Restore string length
	mov	cx,ax		;Temp storage
	lahf			;Save value returned by stre_cmp
	add	si,cx		;SI := trailer
	pop	cx		;Restore pattern length
	sahf			;Restore stre_cmp result
	jne	@strstk_fwd_match_10 ;No match, loop back
	clc			;No errors
	jmp	short @strstk_fwd_match_99

@strstk_fwd_match_90:
	stc			;Error return
@strstk_fwd_match_99:
	mov	[bx].cur,si
	@restore
	ret
strstk_fwd_match endp


;+
; FUNCTION : strstk_bck_match
;
;	Searches towards the bottom of the stack, starting from the string
;	below the current string looking for a string that has the specified
;	pattern as a prefix.  If the pattern length is 0, then the match is
;	universal and the new current string is simply the one immediately
;	below the current one.  The function can thus be used to move the
;	cur pointer down the stack one string at a time. If the current
;	string is at the bottom of the stack, the cur pointer remains
;	unchanged.
;
; Parameters:
;	BX :=	address of buffer stack descriptor
;	AX :=	Address of pattern
;	CX :=	Length of pattern 
; Returns:
;	CF  = 1 if no match or if at bottom of stack
;	    = 0 if success
;
; Registers AX,CX destroyed.
;-
strstk_bck_match proc near
	@save	si,di
	push	bp
	mov	bp,sp
	sub	sp,2
sentinel EQU <word ptr [bp-2]>
	push	ax		;remember pattern address
	mov	di,[bx].low_end	;Buffer bottom
	inc	di
	mov	si,[bx].cur	;SI:=current pointer
	cmp	si,di		;At stack bottom ? ( low_end + 1 == cur)
	je	@strstk_bck_match_90 ;If so exit,
				; (the 'push AX' is cleaned up by unlink)
	mov	sentinel,di	;remember sentinel value

	pop	di		;Restore pattern address

; Prime for loop below
	xor	ah,ah
	mov	al,[si]		;AX<-length of current string
	sub	si,ax		;SI->start of string

@strstk_bck_match_9:
; Loop begin. SI points to the first byte of string last compared. This
; cannot be the sentinel string.
	dec	si		;SI->header of current string
	dec	si		;SI->trailer of previous string

@strstk_bck_match_10:
; At this point SI points to the trailer of string to try'n'match
	cmp	si,sentinel	;Are we at bottom ?
	je	@strstk_bck_match_90 ;Yes, exit
	mov	al,[si]		;String length
	xor	ah,ah
	sub	si,ax		;Point to first byte of string
	cmp	ax,cx		;Is the pattern longer than string ?
	jb	@strstk_bck_match_9 ;Yes, then try next string
				;OK, try see if pattern is the string prefix
	push	cx		;Remember pattern length

⌨️ 快捷键说明

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