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

📄 cmdmacro.asm

📁 random.zip 随机数产生器的汇编源代码 cmdsrc.zip 一个文本编辑器的汇编源代码
💻 ASM
📖 第 1 页 / 共 3 页
字号:
; CMDMACRO.ASM
; (c) 1989, 1990 Ashok P. Nadkarni
;
; Module implementing macro and symbol feature for CMDEDIT.
;
; Symbols :
; CMDEDIT symbols can be defined either from the command line or read
; from a file during initialization. The syntax is given by
;	defs symbolname expansion
; When the defined symbol appears as the first word in the line, it is
; replaced by its expansion. The rest of the line is unchanged. The
; following line defines a symbol called 'ed' that runs my editor.
;
;	defs ed c:\util\editor
;
; Now if you type
;
;	ed newfile
;
; the command
;
;	c:\util\editor newfile
;
; will be executed.
;
; Symbols are expanded recursively.
;
; Macros :
;
; CMDEDIT macros can be defined either from the command line or read
; from a macro file when CMDEDIT is installed. In both cases, macros
; are defined using the same syntax. Macros may expand into multiple 
; lines. In the latter case, each line of the expansion in passed to 
; the calling application one at a time.
;
; Macros are defined using the CMDEDIT command 'defm' followed by the
; macro name. The macro name is separated from the 'defm' keyword by one 
; or more spaces/tabs. Any characters after the name of the macro are ignored.
; Each line of the macro expansion is defined on a separate line. The
; expansion may contain any number of lines (limited by buffer space)
; and is terminated by a line that begins with the keyword 'endm'. For
; example, the following lines define a macro that will change the
; current directory from any disk:
;	defm gotc
;	c:
;	cd \TURBOC
;	endm
; Macro keywords are case-insensitive.
;
; Macro Parameters:
;	Similar to batch files, macros can be passed parameters. (Read
; your DOS manual to find out about parameters). Although the
; concept is similar to DOS batch files, CMDEDIT parameters behave a
; little differently. Upto 9 parameters can be defined. These are
; indicated in macro definitions as '%n' where n is a digit from 1 to 9.
; A parameter can appear anywhere in the definition and need
; not be surrounded by whitespace. Also, the character % itself can be
; placed anywhere in the definition as long as it is not followed by a
; digit. If you do want a '%n' sequence in the expansion, indicate the '%'
; character as '%%'.
; For example, consider
;	defm bf 
;	copy %1 a:\%1\%%1
;	endm
; Then, when you type
;	"bf myfile"
; the macro will expand to
;	"copy myfile a:\myfile\%1"
; Note how %1 has been replaced by 'myfile' in two places but not the third.
;
; A macro cannot call another macro except if the call is the last
; line in the macro. Macros anywhere else are not expanded and the line
; is passed to the calling application without modification.
;
; Note that the macro name can be null as well. In this case, hitting
; carraige return on an blank line will result in that macro being run.

	INCLUDE common.inc
	INCLUDE general.inc
	INCLUDE ascii.inc
	INCLUDE dos.inc

	PUBLIC	macro_init
	PUBLIC	symbol_init
	PUBLIC	execute_defm
	PUBLIC	execute_defs
	PUBLIC	execute_delm
	PUBLIC	execute_dels
	PUBLIC	execute_rstsym
	PUBLIC	execute_rstmac
	PUBLIC	execute_cmdstat
	PUBLIC	get_macro_line
	PUBLIC	expand_macro
	PUBLIC	expand_symbol
	PUBLIC	expand_var
	PUBLIC	get_symbol
	PUBLIC	mac_stk
	PUBLIC	sym_stk
	PUBLIC	ismacsym

PLACEHOLDER equ PERCENT				;Placeholder character

	INCLUDE buffers.inc

CSEG	SEGMENT	PARA PUBLIC 'CODE'
DGROUP	GROUP	CSEG

	EXTRN	endm_cmd:BYTE
	EXTRN	defm:BYTE
	EXTRN	defs:BYTE
	EXTRN	get_kbd_line:ABS
	EXTRN	source:WORD
	EXTRN	macro_level:WORD
	EXTRN	macro_ignore_char:BYTE
	EXTRN	lastchar:WORD
	EXTRN	linebuf:BYTE
	EXTRN	dot:WORD
	EXTRN	LINEBUF_END:ABS
	EXTRN	cur_macro:BYTE
	EXTRN	cur_macro_len:WORD

mac_stk $string_stack	<>		;Descriptor for macro buffer
sym_stk	$string_stack	<>		;Descriptor for sym buffer
separator db	13			;Separator string between macros
sep_len	equ	$-separator		;Length of separator string
macro_noroom_msg db 'Table full. Definition ignored.',CR,LF,DOLLAR
macro_prompt	db  CR,LF,'DEFM>',DOLLAR


	EXTRN	push_word:PROC
	EXTRN	push_string:PROC
	EXTRN	get_next_line:PROC
	EXTRN	reset_line:PROC
	EXTRN	abort_processing:PROC
	EXTRN	getargs:PROC
	EXTRN	stre_cmp:PROC
	EXTRN	set_disp_marks:PROC
	EXTRN	isspace:PROC
	EXTRN	isdelim:PROC
	EXTRN	skip_whitespace:PROC
	EXTRN	skip_nonwhite:PROC
	EXTRN	skip_nondelim:PROC
	EXTRN	makeroom:PROC
	EXTRN	remove_chars:PROC
	EXTRN	insert_chars:PROC
	EXTRN	output_counted_string:PROC
	EXTRN	output_newline:PROC
	EXTRN	locate_dosenv:PROC

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


;+
; FUNCTION : macro_init,symbol_init
;
; Initializes the various data structures associated with the
; macro /symbol buffer. CALLER MUST ENSURE PASSED ADDRESSES ARE VALID
; AND BUFFER IS LARGE ENOUGH.
;
; Parameters:
;	AX 	- length of buffer in bytes
;	BX	- address of buffer
;
; Returns:
;	Nothing.
; Registers destroyed :
;	BX
;-
macro_init proc	near
	push	bx
	mov	bx,offset DGROUP:mac_stk ;bx := address of buffer descriptors
	jmp	short @macsym_init
symbol_init LABEL near
	push	bx
	mov	bx,offset DGROUP:sym_stk ;bx := address of buffer descriptors
@macsym_init:
	xchg	ax,cx			;CX = buffer size
	pop	ax			;AX = Buffer address
					;BX points to appropriate descriptor
	call	near ptr strstk_init	;Initialize buffer and descriptor

;Store a separator into the macro buffer
	call	near ptr separate

	ret
macro_init	endp





;+
; FUNCTION : execute_rstmac, execute_rstsym
;
; Resets the various data structures associated with the
; macro /symbol buffer.
;
; Parameters:
;	None.
;
; Returns:
;	Nothing.
;
; Registers destroyed :
;	AX,CX,BX,DX
;-
rst_macsym proc near
execute_rstmac LABEL near
;	mov	macro_level,0
	mov	bx,offset DGROUP:mac_stk ;bx := address of buffer descriptors
	jmp	short @rst_macsym
execute_rstsym LABEL near
	mov	bx,offset DGROUP:sym_stk ;bx := address of buffer descriptors
@rst_macsym:
	call	near ptr strstk_reset	;Re-initialize buffer and descriptor

;Store a separator into the macro buffer
	call	near ptr separate
	ret
rst_macsym	endp




;+
; FUNCTION : ismacsym
;
;	Called to check if the passed string is a valid symbol or macro
;	name. If found, the symbol/macro string stack pointer is set to the
;	first line of the expansion of the symbol/macro.
;
; Parameters:
;	AX	- length of symbol name to be checked
;	BX	- address of the string stack descriptor (symbol or macro)
;	SI	- pointer to the symbol to be checked.
;
; Returns:
;	CF	- 1 if symbol not found, the string stack current pointer
;		  is undefined
;		  0 if symbol found. The string stack pointer points to the
;		  first line of the expansion of the found symbol/macro.
; Register(s) destroyed:
;	AX,CX,DX
;-
ismacsym proc near
	@save	si,di

	mov	di,ax			;DI<-length of symbol
	call	near ptr strstk_settop	;Reset macro stack pointer

@ismacsym_20:
; Loop start, DI = num chars in word, SI->start of word

	mov	ax,si			;AX->word
	mov	cx,di			;CX<-length of word
	call	near ptr strstk_bck_find ;Look backward for string
;					 Params AX,BX,CX
;					 BX unchanged
	jc	@ismacsym_98		;Not found so return with CF set
;	The name matched. Now make sure it is a macro name by ensuring
;	previous string is a separator.
	xor	cx,cx			;cx<-length of pattern
	call	near ptr strstk_bck_match ;Set current to previous string
;					 BX unchanged
	jc	@ismacsym_98		;start of buffer so return
;					 with CF set
	push	bx
	call	near ptr check_separator
	pop	bx
	je	@ismacsym_50		;This is the one
;	Wasn't a separator. Move back over it to start the hunt again.
	xor	cx,cx
	call	near ptr strstk_fwd_match
	jmp	short @ismacsym_20

@ismacsym_50:
; The macro/symbol has been found.
	xor	cx,cx			;CX<-match length
	call	near ptr strstk_fwd_match ;Skip over separator
	xor	cx,cx			;CX<-match length
	call	near ptr strstk_fwd_match ;Skip over macro/symbol name
	clc				;Clear return flag
@ismacsym_98:
	@restore
	ret
ismacsym endp



;+
; FUNCTION : execute_dels, execute_delm
;
;	execute_dels and execute_delm respectively delete symbols and
;	macros from the appropriate stack. All symbols/macros listed on the
;	line are deleted. If a particular symbol/macro is not defined, no
;	error is generated.
;	
; 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
del_macsym proc near
execute_dels LABEL near
	mov	bx,offset DGROUP:sym_stk
	jmp	short @del_macsym_5
execute_delm LABEL near
	cmp	macro_level,1
	jne	@execute_delm_1
	mov	ax,E_NESTED_DELM
	jmp	near ptr abort_processing
@execute_delm_1:
	mov	bx,offset DGROUP:mac_stk
@del_macsym_5:
	@save	si,di
	push	bp
	mov	bp,sp
	sub	sp,2
num_remain equ <word ptr [bp-2]>
;
@del_macsym_10:
; At this point, SI->remaining chars in line, CX is number of chars
	jcxz	@del_macsym_99			;No more chars in line
;	Find first word
	push	bx				;Save buffer descriptor addr
	call	near ptr skip_whitespace	;SI->first non blank
	mov	di,si				;DI->start of word
	call	near ptr skip_nondelim		;SI->char after word
	mov	ax,si				;
	xchg	si,di				;SI->word, DI->rest of line
	sub	ax,si				;AX<-num chars in word
	pop	bx				;BX->buffer descriptor
	push	cx				;Save remaining count
	call	near ptr ismacsym		;Is it in macro/symbol stack ?
	pop	cx				;Restore remaining count
	mov	si,di				;SI->rest of line
	jc	@del_macsym_10			;Not found so go onto next
;						 symbol 
; The macro or symbol has been found. The current stack pointer is the
; first line of the expansion. Move it down to the separator just before
; the macro or symbol name itself. Then keep deleting strings from the
; stack until we hit another separator.
	push	cx				;Save remaining count
	xor	cx,cx
	call	near ptr strstk_bck_match	;Point to name
	xor	cx,cx
	call	near ptr strstk_bck_match	;Point to separator
@del_macsym_20:
	call	near ptr strstk_kill		;Delete the string
;	Check if separator
	call	near ptr check_separator	;Is new 'current' a
;						 separator ?
	jne	@del_macsym_20			;No, so keep deleting
;	Reached a separator.
	pop	cx				;Restore count
	jmp	short @del_macsym_10		;Keep looping for rest of line

@del_macsym_99:
	mov	sp,bp
	pop	bp
	@restore
	ret
del_macsym endp



;+
; FUNCTION : expand_macro, expand_symbol
;
;	expand_macro and expand_symbol attempt expand the first word in
;	linebuf as a macro name and symbol respectively. If no macro
;	expansion is going on, the expand_macro routine will attempt to
;	expand the first word in the line buffer as a macro (leading
;	whitespace is ignored). If an expansion is found, it is stored
;	in the line buffer with the parameters (if any) filled in. If
;	there is already a macro expansion going on or no macro is
;	found, the line buffer is unchanged.
;
;	In contrast, the expand_symbol routine always tries to
;	expand the first word as a symbol.
;
;	If the first character of the line is a macro_ignore_char, the
;	character is removed, the rest of the line moved up and no
;	expansions are done.
;
; Parameters:
;
; Returns:
;	CF =	0 if line buffer changed
;		1 otherwise (no macro/symbol or ongoing macro expansion)
;
; Register(s) destroyed:
; AX,BX,CX,DX
;-
expand_macro proc near
	mov	bx,offset DGROUP:mac_stk ;BX->macro descriptor
	jmp	short @expand
expand_symbol LABEL near
	mov	bx,offset DGROUP:sym_stk ;BX->symbol descriptor
@expand:
	push	si
	push	di
	push	bp
	mov	bp,sp
	sub	sp,2
num_remain  equ <word ptr [bp-2]>

	cmp	bx,offset DGROUP:mac_stk
	jne	@expand_10		;If symbol, don't worry about
;					 whether any macro expansions
;					 are ongoing
	cmp	macro_level,0		;Already expanding a macro?
	je	@expand_10		;No macro expansion currently ongoing
	stc				;set CF to indicate no expansion
	jmp	@expand_98		;Yes, exit with carry flag set

@expand_10:
; Look back through the macro/symbol stack buffer for a macro definition.
	
;	Find first word of line.
	push	bx			;Save buffer descriptor addr
	mov	cx,lastchar		;End of line
	mov	si,offset DGROUP:linebuf ;SI->line buffer
	sub	cx,si			;CX<-length of line
	call	near ptr skip_whitespace ;SI->first non blank
	mov	di,si			;DI->start of word
	call	near ptr skip_nondelim	;SI->char after word
	mov	num_remain,cx		;Remember num chars remaining
;					 in line
	mov	ax,si			;
	mov	si,di			;SI->word
	sub	ax,si			;AX<-num chars in word
	pop	bx			;BX->buffer descriptor
	call	near ptr ismacsym	;Is it in macro/symbol stack ?
	jc	@expand_98		;Not found so return with CF set
; The macro or symbol has been found.

; CHeck if it is the macro/symbol string stack
	cmp	bx,offset DGROUP:mac_stk  ;Expanding a macro ?
	jne	@expand_50		;No, expanding symbol

	mov	macro_level,1		;Indicate expansion going on
;	Copy linebuf into cur_macro (to remember arguments)
	mov	di,offset DGROUP:cur_macro
	mov	si,offset DGROUP:linebuf
	mov	cx,lastchar
	sub	cx,si			;CX<-length of linebuf
	mov	cur_macro_len,cx	;Store length of invocation line
	rep	movsb			;Remember macro invocation line
; The current stack string is the first expansion line of the macro
	mov	sp,bp			;clean up stack
	pop	bp			;restore registers
	pop	di
	pop	si
	jmp	short get_macro_line	;Yes, copy it into the linebuf buffer
;	get_macro_line will return to caller with  the appropriate value
;	of the carry flag.

@expand_50:
; We are expanding a symbol.
; num_remain = num chars in linebuf after symbol
; First we move these characters to the end of the buffer

	mov	cx,num_remain		;CX<-number of chars to move back

	call	near ptr makeroom	;Make room in buffer	
	mov	si,di			;SI->chars copied to the back
;	Now copy the string
	mov	ax,offset DGROUP:linebuf ;AX->line buffer
	mov	cx,LINEBUF_SIZE		;CX<-size of line buffer
	call	near ptr strstk_copy	;Copy line. Never mind if end
;					 string overwritten.
;					 AX<-length of expanded string
	mov	di,offset DGROUP:linebuf
	add	di,ax			;DI->location after expansion
	mov	cx,num_remain		;CX<-num chars to copy after expansion
	add	ax,cx			;ax<-total length of line
	cmp	ax,LINEBUF_SIZE		;End chars overwritten ?
	jbe	@expand_60
	mov	ax,E_TRUNCATE		;Truncation error
	jmp	near ptr abort_processing
@expand_60:
; Copy trailing chars to end of expansion
	rep	movsb
	mov	lastchar,di
	mov	dot,di
	clc				;Indicate expansion took place
@expand_98:
; MUST NOT CHANGE CARRY FLAG AFTER THIS POINT.
	mov	sp,bp			;clean up stack
	pop	bp			;restore registers
	pop	di
	pop	si
	ret
expand_macro	endp




;+
; FUNCTION : get_macro_line
;
;	Copies a line from the macro stack to linebuf. All parameters
;	codes (%1, %2 etc.) are replaced with their corresponding
;	parameters. If this line is the last in the macro definition,
;	the macro_level flag is reset. This allows the last line in a

⌨️ 快捷键说明

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