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

📄 cmdmacro.asm

📁 用汇编语言实现的一个文本编辑器
💻 ASM
📖 第 1 页 / 共 3 页
字号:
;	macro definition to be treated as a macro itself. In case of
;	any errors( eg. expansion too long), the macro expansion is
;	aborted and the input is directed to the keyboard.
;
; Parameters:
;	None.
;
; Returns:
;	CF	= 0 if a line copied to linebuf
;		  1 if no more lines in expansion or no ongoing expansion
; Register(s) destroyed:
;	AX,BX,CX,DX
;-
get_macro_line	proc near
	cmp	macro_level,0		;Expanding a macro ?
	jne	@get_macro_line_1	;Yes
	stc				;CF = 1 for no expansion
	ret
@get_macro_line_1:
	push	si
	push	di
	push	bp
	mov	bp,sp
	sub	sp,LINEBUF_SIZE
tempbuf	equ	<byte ptr [bp-LINEBUF_SIZE]>

; Copy the current string from the macro buffer into temp buffer.
	mov	bx,offset DGROUP:mac_stk ;BX->address of buffer descriptors
	lea	ax,tempbuf		;AX->destination address
	mov	cx,LINEBUF_SIZE		;CX<-size of buffer
	call	near ptr strstk_copy	;Copy macro into temp buffer
					;AX<-length of expansion
					; No error possible
; Replace any placeholders in the macro line by the corresponding paramters.
; copy all chars until first placeholder. Copy argument.
; Repeat for whole expansion. If at any time there is no place in
; buffer, then abort.
	xchg	cx,ax			;CX<-length of expansion
	lea	si,tempbuf		;SI->tempbuf (macro expansion)
	mov	di,offset DGROUP:linebuf ;DI->linebuf
@get_macro_line_38:
	jcxz	@get_macro_line_60	;Jump if no more expansion

@get_macro_line_40:
; At the start of the loop, the following hold :
; DI->next empty location in the linebuf
; SI->next char of macro expansion to be examined (in tempbuf)
; CX = remaining number of chars in expansion (> 0)
	mov	al,PLACEHOLDER		;Going to search for placeholder
	mov	dx,cx			;DX<-length of remaining expansion
	push	di			;Save DI
	mov	di,si			;DI->start point for
;					 placeholder scan
	repne	scasb			;Look for placeholder
					;assumes! (ES == SS)
;	CX is number of chars after placeholder
	sub	dx,cx			;DX<-num chars to be copied
	xchg	dx,cx			;CX<-num chars to be copied
					;DX<-num chars after placeholder
	pop	di			;DI->destination in linebuf
	rep	movsb			;Move chars from tempbuf to linebuf
					;assumes! (ES == SS)
;	Note we don't care if the characters at the end of the linebuf
;	are overwritten.
	mov	cx,dx			;CX<-remaining number of chars
	jcxz	@get_macro_line_60	;All chars copied (placeholder
					; not found or last char in line)
;	We have found a placeholder character in tempbuf. SI points to the 
;	character AFTER the placeholder. Based on the JCXZ above, there
;	is at least one character after the placeholder. If it is a
;	char between '0' and '9' then it is a genuine placeholder. If
;	it is another placeholder character, then a single placeholder
;	is stored. Else both the placeholder as well as the character
;	will be stored into linebuf.
	mov	al,[si]			;AL<-char after placeholder
	cmp	al,PLACEHOLDER		;Is it a placeholder ?
	jne	@get_macro_line_45	;No
;	Skip over second placeholder
	inc	si
	loop	@get_macro_line_40
	jmp	short @get_macro_line_60 ;No more chars in expansion
@get_macro_line_45:
	cmp	al,'9'
	ja	@get_macro_line_40	;Not a digit
	sub	al,'0'-1		;Compaer with '0'. At the same
;					 time translate '0'->1,'1'->2
;					 ..and so on to '9'->10 since
;					 getargs counts from 1, not 0.
	jbe	@get_macro_line_40	;Not a digit
	dec	di			;Cancel stored PLACEHOLDER char
	push	cx			;Save CX
	mov	bx,di			;BX->destination for argument
	mov	dx,LINEBUF_END
	sub	dx,bx			;DX<-remaining space in buffer
	mov	di,si			;Save SI in DI
	mov	si,offset DGROUP:cur_macro ;SI->current macro being expanded
	xor	ah,ah			;AX<-arg number (AL already
;					 holds actual arg number)
	mov	cx,cur_macro_len	;Length of original macro string
	call	near ptr getargs	;Get the argument into linebuf
					;AX<-num chars copied, BX unchanged
					;CF indicates error condition
	pop	cx			;Restore CX (num remaining
;					 chars in macro expansion)
	mov	si,di			;Restore SI
;					(SI->char AFTER placeholder char)
	mov	di,bx			;Start of copied characters
	jc	@get_macro_line_101	;Jump if getargs returned error
@get_macro_line_50:
	add	di,ax			;DI->next destination char in linebuf
	inc	si			;SI->next char of macro expansion
	loop	@get_macro_line_40	;Decrement remaing characters

@get_macro_line_60:

	mov	lastchar,di			;Update end of line
	mov	dot,di				;Update cursor
; Set the lastchar and display end pointers
	IF	0
	Currently no need to set display pointers since macro lines are
	not displayed
	mov	ax,di				;AX->Potential disp_end
	mov	dx,offset DGROUP:linebuf 	;Potential disp_begin
	call	near ptr set_disp_marks		;Set the marks
	ENDIF

; Finally check to see if this line is the last in the macro expansion.
	mov	bx,offset DGROUP:mac_stk ;BX->macro stack descriptor
	xor	cx,cx			;Move to next string in stack
	call	near ptr strstk_fwd_match
	call	near ptr check_separator ;Is this the last line of
;					  expansion ?
	jne	@get_macro_line_90	;No

; This was the last line in the macro expansion. Reset macro flag
	mov	macro_level,0		;Reset flag
@get_macro_line_90:
;	@unlink
	mov	sp,bp			;clean up stack
	pop	bp			;restore registers
	pop	di
	pop	si
	clc				;Return macro expanded
	ret

@get_macro_line_101:
; truncation error
	mov	ax,E_TRUNCATE		;Indicate truncation of line
	jmp	near ptr abort_processing

get_macro_line	endp




;+
; FUNCTION : check_separator
;
;	Checks to see if the current macro/symbol buffer line is a
;	separator.
;
; Parameters:
;	BX	= address of macro/symbol stack descriptor
;
; Returns:
;	ZF = 1 if current buffer line is the separator string
;	     0 otherwise.
;
; Register(s) destroyed:
;	AX,CX
;-
check_separator proc near
	mov	ax,offset DGROUP:separator
	mov	cx,sep_len
	call	near ptr strstk_compare	;Is it the separator ?
;	strstk_comapre sets ZF.
	ret
check_separator endp




;+
; FUNCTION : execute_defs
;
;	Called to define a symbol.
;
; 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_defs	proc near
	mov	bx,offset DGROUP:sym_stk	;BX->stack descriptor
; Push macro name
	call	near ptr push_word		;Push first word onto
;						 the stack. Params :
;						 SI->string
;						 CX=num chars
;						 Returns:
;						 AX<-status code
;						 SI->char after word
;						 CX<-num remaining chars
	cmp	ax,0				;Check status
	jg	@execute_defs_99		;No word on line,
;						 ignore command
	jl	@execute_defs_109		;No room in stack

; Now push the rest of the string as is except that leading whitespace
; is compressed.
	call	near ptr skip_whitespace	;Skip leading whitespace
						;Params SI, CX
						;Returns SI->first
;						 non-white space char
;						 CX<-remaining chars
;						 (maybe 0)
	call	near ptr push_string		;Push string onto stack
;						 (maybe null string)
	jc	@execute_defs_109		;No room in stack
	call	near ptr cmdsym_separate	;Push separator onto stack
	jc	@execute_defs_109		;No room in stack
@execute_defs_99:
	ret

@execute_defs_109:
; Error. No room in macro stack.
	call	near ptr cmdsym_cleanup		;Clear out partial definition
	call	near ptr disp_noroom	;Display error
	ret
execute_defs	endp


;+
; FUNCTION : execute_defm
;
;	Called to define a multiple line macro. This function will
;	keep reading from the current input source and storing it in
;	the macro buffer until an `endm' is seen. The ENDM directive
;	can be followed by any characters (eg. macro name)
;
; 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_defm	proc near
	mov	ax,E_NESTED_MACRO	;Assume error
	cmp	macro_level,0		;Expanding a macro ?
	je	@execute_defm_1		;No, jump
	jmp	near ptr abort_processing ;Yes, nested macro error
@execute_defm_1:
	@save	si,di
	push	bp
	mov	bp,sp
	sub	sp,2
err_flag equ <word ptr [bp-2]>
	mov	bx,offset DGROUP:mac_stk	;BX->stack descriptor
	mov	err_flag,0			;Initially no errors

; If expanding a macro, ignore all lines until an endm
	cmp	macro_level,0
	jnz	@execute_defm_5			;Go set error flag

; Push macro name
	call	near ptr push_word		;Push first word onto
;						 the stack. Params :
;						 SI->string
;						 CX=num chars
;						 Returns:
;						 AX<-status code
;						 SI->char after word
;						 CX<-num remaining chars
	cmp	ax,0				;Check status
	jb	@execute_defm_5			;No room in stack
	je	@execute_defm_40		;No errors
; No name for macro. Push a 0 length macro name. Macro can be called by
; a blank line
	xor	cx,cx				;CX<-0 (length of string)
	call	near ptr push_string		;Push onto stack
	jnc	@execute_defm_40		;No errors

@execute_defm_5:
	mov	err_flag,1			;Indicate error
	call	near ptr cmdmacro_cleanup	;Cleanup macro fragments

@execute_defm_40:
; Keep reading lines from the input and store in macro buffer unless an error
; has been previously seen.

; 	Prompt is displayed only if reading from the keyboard.
	cmp	source,offset DGROUP:get_kbd_line
	jne	@execute_defm_42
	@DispStr macro_prompt
	call	near ptr reset_line
@execute_defm_42:
	call	near ptr get_next_line
	mov	si,offset DGROUP:linebuf	;SI->String to push
	mov	cx,lastchar
	sub	cx,si				;CX<-length of line
	push	si				;Remember SI and CX
	push	cx
	call	near ptr skip_whitespace	;SI->first non-white
						;CX<-num remaining chars
	jcxz	@execute_defm_50		;Blank line so go store it
	mov	di,si				;DI->start of word
	call	near ptr skip_nonwhite
	mov	cx,si
	sub	cx,di				;CX<-length of word
	xor	ah,ah
	mov	si,offset DGROUP:endm_cmd
	lodsb					;AX<-length of endm command
	cmp	cx,ax
	jne	@execute_defm_50		;Not ENDM
	call	near ptr stre_cmp		;Compare strings
	jnz	@execute_defm_50
; ENDM seen.
	cmp	err_flag,1			;Had we seen an error ?
	jne	@execute_defm_45		;No
	call	near ptr disp_noroom	;Display error
	jmp	short @execute_defm_99
@execute_defm_45:
; End of macro seen. Store macro separator
	call	near ptr cmdmacro_separate
	jmp	short @execute_defm_99

@execute_defm_50:
; Store line in macro buffer
	pop	cx				;CX<-length of line
	pop	si				;SI->linebuf
	mov	bx,offset DGROUP:mac_stk	;BX->stack descriptor
	call	near ptr push_string
	jnc	@execute_defm_40		;No error
	jmp	short @execute_defm_5		;Indicate error

@execute_defm_99:

	mov	sp,bp
	pop	bp
	@restore
	ret
execute_defm endp




;+
; FUNCTION : cmdmacro_separate,cmdsym_separate,separate
;
;	Pushes a separator string onto the stack.
;
; Parameters:
;	None for cmdmacro_separate and cmdsym_separate
;	BX->buffer descriptor for routine separate
; Returns:
;	CF	= 1 if no room in stack
;		  0 otherwise
;
; Register(s) destroyed:
;	AX,BX,CX,DX
;-
cmdmacro_separate proc near
	mov	bx,offset DGROUP:mac_stk	;BX->stack descriptor
	jmp	short separate
cmdsym_separate LABEL near
	mov	bx,offset DGROUP:sym_stk	;BX->stack descriptor
separate	LABEL near
	mov	ax,sep_len			;AX<-length of separaot string
	mov	dx,offset DGROUP:separator	;DX->separator string
	mov	cx,1				;Force push onto stack
	call	near ptr strstk_push		;Returns status in CF
	ret
cmdmacro_separate endp




;+
; FUNCTION : cmdmacro_cleanup,cmdsym_cleanup
;
;	This function is called to clean up the top of the macro or symbol
;	stacks when a complete definition cannot be pushed onto the
;	stack due to lack of space. The routine keeps deleting strings
;	from the top of the macro stack until it finds a separator string.
;
; Parameters:
;	None.
;
; Returns:
;	Nothing.
;
; Register(s) destroyed:
;	AX,BX,CX,DX
;-
cmdmacro_cleanup proc near
	mov	bx,offset DGROUP:mac_stk	;BX->stack descriptor
	jmp	short @cleanup_5
cmdsym_cleanup	LABEL near
	mov	bx,offset DGROUP:sym_stk	;BX->stack descriptor
@cleanup_5:
	call	near ptr strstk_settop		;Reset cur pointer
;						 BX unchanged
; While the top of stack is not a separator, keep killing strings.
@cleanup_10:
	call	near ptr check_separator
;	mov	ax,offset DGROUP:separator	;AX->separator string
;	mov	cx,sep_len			;CX<-length of separator
;	call	near ptr strstk_compare		;Is this a separator ?
	je	@cleanup_99			;Yes, then all done
	call	near ptr strstk_kill		;Kill string
	jmp	short @cleanup_10		;Keep going
@cleanup_99:
	ret
cmdmacro_cleanup endp




;+
; FUNCTION : disp_noroom
;
;	Displays a message saying there is no room in the macro buffer.
;
; Parameters:
;	None.
;
; Returns:
;	Nothing.
; Register(s) destroyed:
;	AX,DX
;-
disp_noroom proc near
	@DispStr macro_noroom_msg
	ret
disp_noroom endp







;+
; FUNCTION : search_variable
;
;	Called to search the passed string for a variable. A variable is a
;	sequence of characters starting with the VAR_MARKER character
;	followed by another VAR_MARKER character. Two marker characters in
;	succession are left untouched. (This is so that this routine can be
;	called again to check for more variables.)
;
; Parameters:
;	SI	- points to the string.
;	AX	- length of the string.
;
; Returns:
;	SI	- Points to first marker character of variable if AX is not 0
;		  else points to end of string.
;	AX	- length of variable (including marker chars) if
;		  variable is present, else 0
; Register(s) destroyed:
;	CX
;-
search_variable proc near
	@save	di
	mov	cx,ax
	
@search_variable_10:
	mov	di,si				;DI->string to search
;						 CX is number of chars
; Note we are OK if length of line is already 0.	
	mov	al,VAR_MARKER
	repne scasb				;Search for marker
; If marker not found or found in last position, CX will be 0.
	jcxz	@search_variable_99
; DI->char after first marker, CX is remaining number of characters
	mov	si,di
@search_variable_20:
	lodsb					;AL<-next char
	dec	cx
	jcxz	@search_variable_99		;If there was only one char
;						 after the marker, variable
;						 not possible
	cmp	al,VAR_MARKER			;Is it a marker ?
	je	@search_variable_10		;Yes, found a marker, just
;						 ignore the pair and keep
;						 looking
; We have found the start of a variable. Look for its end.
	inc	di				;Move past first char of var
	mov	al,VAR_MARKER
	repne	scasb				;Look for it
	jne	@search_variable_99		;Not found (CX is 0)
; Found a variable
	dec	si
	dec	si				;SI->start marker of var
	mov	cx,di
	sub	cx,si				;CX<-length of var

@search_variable_99:
	xchg	ax,cx				;AX<-length of var
	@restore

⌨️ 快捷键说明

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