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

📄 cmdmacro.asm

📁 用汇编语言实现的一个文本编辑器
💻 ASM
📖 第 1 页 / 共 3 页
字号:
	ret
search_variable	endp




;+
; FUNCTION : get_symbol
;
;	Hunts through the symbol stack looking for a match for the passed
;	symbol. If found, it is returned in passed buffer.
;
; Parameters:
;	SI	- points to the symbol
;	AX	- length of symbol
;	DI	- points to the expansion buffer
;	DX	- size of buffer
;
; Returns:
;	CF	- 1 symbol not found (AX set to 0) or [DI] buffer to small
;		  to hold expansion (AX contains actual length of expansion).
;		  0 symbol found. Its expansion is stored in [DI] with
;		  length in AX.
; Register(s) destroyed:
;	AX,BX,CX,DX
;-
get_symbol proc near
	@save	si
	mov	bx,offset DGROUP:sym_stk	;BX->symbol stack
	push	dx				;Save DX
	call	near ptr ismacsym		;Is it a symbol ?
	pop	cx				;CX<-size of buffer
	jnc	@get_symbol_20			;Yes, go on
	xor	ax,ax				;No, not a symbol
	stc					;Set CF to indicate error
	jmp	short @get_symbol_99

@get_symbol_20:
; Symbol has been found. The current symbol stack pointer has been set to
; its expansion string.
	mov	ax,di				;AX->buffer
	call	near ptr strstk_copy		;Params
;						 BX->stack descriptor
;						 AX->buffer
;						 CX->size of buffer
;						 Returns CF set if
;						 truncation error.
;						 AX always set to length of
;						 actual expansion.
;	CF set/reset by strstk_copy	

@get_symbol_99:
	@restore
	ret
get_symbol endp





;+
; FUNCTION : get_dosenv
;
;	Hunts through the DOS environment looking for a match for the passed
;	string. If found, it is returned in passed buffer.
;
;	Assumes passed string does NOT contain a NULL byte.
;
; Parameters:
;	SI	- points to the string
;	AX	- length of string
;	DI	- points to the expansion buffer
;	DX	- size of buffer
;
; Returns:
;	CF	- 1 string not found (AX set to 0) or [DI] buffer too small
;		  to hold expansion (AX contains actual length of expansion).
;		  0 symbol found. Its expansion is stored in [DI] with
;		  length in AX.
; Register(s) destroyed:
;	AX,BX,CX,DX
;-
get_dosenv proc near
	@save	si,di,es
	push	bp
	mov	bp,sp
	sub	sp,6
var_len equ <word ptr [bp-2]>
exp_buf equ <word ptr [bp-4]>
exp_buf_len equ <word ptr [bp-6]>
	mov	var_len,ax			;Save length of string
	mov	exp_buf,di			;Save expansion buf address
	mov	exp_buf_len,dx			;Save expansion buf length

	call	near ptr locate_dosenv		;AX->DOS environment segment
	or	ax,ax				;Is it 0?
	je	@get_dosenv_90			;Yes, we do not know DOS env

; We have the DOS segment
	mov	es,ax				;ES->environment segment
	xor	di,di				;ES:DI->base of environment
	mov	cx,8000h			;Max possible environ size
;						 is 32K 

@get_dosenv_10:
; Top of env search loop. DI contains offset into environment. SI points to
; string. DI actually points to start of an env var name if any. CX is
; remaining bytes in environment (> 0)
	cmp	byte ptr es:[di],0		;End of environment?
	je	@get_dosenv_89			;Yes

; We are just going to call stre_cmp to compare strings. Does not matter if
; the environment or environment var ends before then since the comparison
; will fail since we are assuming a null byte does not occur in the string
; that was passed to us.
	push	cx				;Remember how much
;						 environment left
	mov	cx,var_len			;CX<-length to compare
	call	near ptr stre_cmp		;Params DS:SI, ES:DI, CX
	pop	cx				;CX<-remaining environment size
	je	@get_dosenv_50			;Match so far

; No match. Hunt for the next null byte or end of environment.
@get_dosenv_40:
	xor	al,al
	repne	scasb
	jcxz	@get_dosenv_89			;If no match for null or
;						 match in last byte, exit
	jmp	short @get_dosenv_10		;Keep looking

@get_dosenv_50:
; We have a match so far. The next char in the environ must be a '='.
	mov	ax,var_len
	add	di,ax
	sub	cx,ax
	cmp	byte ptr es:[di],'='
	jne	@get_dosenv_40			;No match

; We have a match.
	inc	di				;DI->start of env expansion
	push	di				;Save DI
	dec	cx				;CX<-remaining length of env
	xor	ax,ax
	repne	scasb				;Hunt for expansion end
	mov	ax,di
	pop	di				;DI->start of expansion
	sub	ax,di
	dec	ax				;AX<-length of expansion
	mov	cx,exp_buf_len			;CX<-size of expansion buffer
	cmp	cx,ax				;Is it too small?
	pushf					;Remember flags
	jb	@get_dosenv_60			;Copy only that many bytes
	mov	cx,ax				;Copy all bytes of expansion
@get_dosenv_60:
; AX contains number of bytes so do not change it after this.
	push	ds				;Save DS
	push	es
	pop	ds
	pop	es
	mov	si,di				;DS:SI->expansion of env var
	mov	di,exp_buf			;ES:DI->expansion buffer
	rep	movsb
	push	es
	pop	ds				;Restore DS. ES is restored
;						 at end of routine.
	popf					;Restore status in CF.
;						 AX already contains
;						 expansion actual byte count
	jmp	short @get_dosenv_99
@get_dosenv_89:
; Not found in environment
	xor	ax,ax
@get_dosenv_90:
; Error. AX must have been already set appropriately.
	stc
@get_dosenv_99:
	mov	sp,bp
	pop	bp
	@restore	
	ret
get_dosenv endp



;+
; FUNCTION: replace_var_markers
;
;	Replaces all double VAR_MARKER characters with single VAR_MARKERs.
;	Any solo VAR_MARKERs are deleted (as in DOS batch files).
;
; Parameters:
;	DI	- points to string
;	CX	- length of string
;
; Returns:
;	AX - new length of string
;
; Registers destroyed:
;	AX,CX,DX
;-
replace_var_markers proc near
	@save	si,di
	mov	dx,cx
	mov	al,VAR_MARKER
@replace_var_markers_9:
	jcxz	@replace_var_markers_99
@replace_var_markers_10:
; CX must not be 0 at this point! Else calculation of DX goes wrong.
	repne	scasb				;Look for marker
	jne	@replace_var_markers_99		;No more markers in string
; Found a marker. Move remaining characters up by 1.
; DI->first char to be moved up, CX is number of chars to move up
	dec	dx				;Deleted one char
	jcxz	@replace_var_markers_99		;No more bytes
	push	cx				;Sace byte count
	push	di				;Save di
	mov	si,di
	dec	di
	rep	movsb				;Move chars up
	pop	di				;DI->next pos to start hunt
	pop	cx				;remaining bytes
	dec	cx				;jump over character that
;						 now occupies the original
;						 marker position.
	jmp	short @replace_var_markers_9

@replace_var_markers_99:
	mov	ax,dx				;AX<-new string length
	@restore
	ret
replace_var_markers endp





;+
; FUNCTION : expand_var
;
;	Expands the variables (if any) present in the current line. A
;	variable consists of a series of non-delimiter characters
;	between two 'VAR_MARKER' characters. The DOS environment block is
;	first checked for the presence of the first such variable in the
;	line and if it is present, it is replaced with its value. Otherwise
;	the CMDEDIT symbols are checked for match. If there is a match, it
;	is replaced with the value of the symbol else, it is replaced by a
;	null string. This procedure is repeated until there are no symbols
;	in the line. Note that the replacements may themselves contain
;	variables which will be replaced in turn. 
;
; Parameters:
;	None.
;
; Returns:
;	CF = 0 if no errors.
;	CF = 1 if errors (line too long). AX contains error code.
; Register(s) destroyed:
;	AX,BX,CX,DX
;-
expand_var proc near
	@save	si,di
	push	bp
	mov	bp,sp
	sub	sp,LINEBUF_SIZE
var_exp equ <byte ptr [bp-LINEBUF_SIZE]>

@expand_var_10:
	mov	si,offset DGROUP:linebuf	;SI->current line
	mov	ax,lastchar
	sub	ax,si				;AX<-length of line
	call	near ptr search_variable	;Look for a var
;						 AX<-length of var
;						 SI-> var
	or	ax,ax				;AX is length of var
	je	@expand_var_60			;No more vars,
; First check the DOS environment for the presence of this variable.
	mov	var_len,ax			;Store var len in var_len
	inc	si				;Move SI past the VAR_MARKER
	dec	ax
	dec	ax				;Do not count the two
;						 VAR_MARKER characters
	lea	di,var_exp			;DI->buffer
	mov	dx,LINEBUF_SIZE			;DX<-size of expansion buffer
	call	near ptr get_dosenv		;Params	 SI->var, AX length
;							 DI->var_exp
;						 Returns expansion in [DI]
;						 AX length of expansion
	or	ax,ax				;Any expansion ?
	jne	@expand_var_50			;Yes - go store in line
; DOS environment did not have the var, now try the CMDEDIT symbol stack.
	mov	ax,var_len
	dec	ax
	dec	ax				;Do not count the two
	mov	dx,LINEBUF_SIZE			;DX<-size of expansion buffer
	call	near ptr get_symbol		;Params SI,AX,DI,DX
;						 Returns expansion in [DI],
;						 length in AX
;	Even if expansion was null, fall thru and replace var with the
;	expansion (possibly null)

@expand_var_50:
; Replace the var pointed to by SI of length var_len by the expansion given
; in var_exp (with length in AX).
	dec	si				;SI->points to marker
	mov	di,ax				;Store AX in DI
	mov	ax,var_len
	call	near ptr remove_chars		;SI,AX parameters
	mov	ax,di				;Restore length of expansion
	mov	di,si				;DI->destination
	lea	si,var_exp
;	push	dot				;Save position
	call	near ptr insert_chars		;SI,DI,AX parameters
;	pop	dot
	jnc	@expand_var_10			;No error
	mov	ax,E_TRUNCATE			;Truncation error
	jmp	short @expand_var_99		;Exit, CF already has status


@expand_var_60:
; All variables have been replaced. Now change all double marker characters
; to single and delete all solo markers (similar to DOS)
	mov	di,offset DGROUP:linebuf	;DI->string
	mov	cx,lastchar
	sub	cx,di				;CX<-length of string
	call	near ptr replace_var_markers
	add	ax,di
	mov	lastchar,ax
	cmp	dot,ax
	jb	@expand_var_80
	mov	dot,ax
@expand_var_80:
	mov	dx,offset DGROUP:linebuf
	call	near ptr set_disp_marks		;Assume all chars changed.
	clc					;CF<-0 (no errors)

@expand_var_99:
;	CF has status
	mov	sp,bp
	pop	bp
	@restore
	ret
expand_var endp



;+
; FUNCTION: disp_until_sep
;
;	This function outputs the contents of the specified stack until the
;	separator is seen. Each element of the stack is followed by a
;	CR-LF. The current pointer is left pointing to the separator.
;
; Parameters:
;	BX	- pointer to stack descriptor
;-
disp_until_sep proc near
	@save	si,di
	push	bp
	mov	bp,sp
	sub	sp,LINEBUF_SIZE+2
display_buf equ <byte ptr [bp-LINEBUF_SIZE]>
sym_kluge equ	<byte ptr [bp-LINEBUF_SIZE-2]> ;Kluge to not output extra
;						space after defs line
	mov	sym_kluge,1

@disp_until_sep_10:
; Start of loop. Check if the current entry is a separator. If so exit.
; Else display the line.
	call	near ptr check_separator
	je	@disp_until_sep_99		;Yes, all done
; Copy the string into the display buffer and display it.
	lea	ax,display_buf
	mov	cx,LINEBUF_SIZE
	call	near ptr strstk_copy
	xchg	cx,ax				;CX<-length of string
	push	bx				;Save BX
	lea	dx,display_buf			;DX->string, CX is count
	call	near ptr output_counted_string
	pop	bx
	cmp	bx,offset DGROUP:mac_stk
	jne	@disp_until_sep_30
	call	near ptr output_newline
	jmp	short @disp_until_sep_32
@disp_until_sep_30:
	cmp	sym_kluge,0
	je	@disp_until_sep_32
	@DispCh	' '
@disp_until_sep_32:
	xor	cx,cx
	call	near ptr strstk_fwd_match
	mov	sym_kluge,0
	jmp	short @disp_until_sep_10

@disp_until_sep_99:
	mov	sp,bp
	pop	bp
	@restore
	ret
disp_until_sep endp



;+
; FUNCTION: output_symbols,output_macros
;
;	Outputs to standard output the current buffer contents of
;	the symbol/macro buffer.
;
; Parameters:
;	None.
;-
output_macsym proc near
output_symbols LABEL near
	mov	bx,offset DGROUP:sym_stk
	mov	ax,offset DGROUP:defs
	jmp	short @output_macsym_5
output_macros LABEL near
	mov	bx,offset DGROUP:mac_stk
	mov	ax,offset DGROUP:defm
@output_macsym_5:
	@save	si,di
	mov	di,ax				;DI->'defs' or 'defm'
	call	near ptr strstk_save_cur	;Save current pointer.
;						 Probably not necessary for
;						 symbols, but do anyway
	call	near ptr strstk_setbot		;Go to bottom of stack

	call	near ptr output_newline

@output_macsym_10:
; Start of loop. One entire macro or symbol has been processed so far.
; The current stack pointer is at the separator. First skip over the separator.
	xor	cx,cx
	call	near ptr strstk_fwd_match
; Try to move one more to make sure there is another string
	xor	cx,cx
	call	near ptr strstk_fwd_match
	jc	@output_macsym_99		;End of buffer
; OK move back to get the name of the symbol / macro.
	xor	cx,cx
	call	near ptr strstk_bck_match
; Now output either 'defs' or 'defm'
	mov	dx,di
	inc	dx				;Point to string
	xor	cx,cx
	mov	cl,[di]				;Length of string
	push	bx				;Save BX
	call	near ptr output_counted_string	;Show command string
	@DispCh	' '				;followed by a space
	pop	bx
;	Now display all strings until a separator is seen
	call	near ptr disp_until_sep

; Now if we are showing a macro, output the 'endm', else a newline
	cmp	bx,offset DGROUP:mac_stk	;Macro ?
	jne	@output_macsym_70		;No, repeat loop
;	Output the 'endm'
	push	bx
	mov	bx,offset DGROUP:endm_cmd
	xor	cx,cx
	mov	cl,[bx]
	mov	dx,bx
	inc	dx
	call	near ptr output_counted_string	;AX,BX,CX,DX destroyed
	pop	bx
	call	near ptr output_newline		;Separate each macro with a
;						 newline 

@output_macsym_70:
	call	near ptr output_newline
	jmp	@output_macsym_10

@output_macsym_99:
	call	near ptr strstk_restore_cur	;Restore the current pointer
	@restore
	ret
output_macsym endp



;+
; FUNCTION: execute_cmdstat
;
;	Displays the current macro and symbol buffer contents.
;
;
; Parameters:
;	SI	-> first char in linebuf following this command
;	CX	== remaining num chars in the line
;
; Returns:
;	Nothing.
;
; Register(s) destroyed:
;	AX,BX,CX,DX
;-
execute_cmdstat proc near
	call	near ptr output_symbols
	call	near ptr output_macros
	call	near ptr output_newline
	ret
execute_cmdstat endp


CSEG	ENDS

	END

⌨️ 快捷键说明

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