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

📄 txtutil.asm

📁 Dos6.0
💻 ASM
📖 第 1 页 / 共 4 页
字号:
					;pass ptr to buffer to ListLine

	push	[lnIncl]		;pass current line
	call	OtxOfLn			;ax = text offset to start of line
	push	ax
	call	OtxNoInclPrev		;ax = otx of $INCLUDE line if this
					; line is from an include file

	push	ax			;pass text offset
	lea	ax,bdBuf
	push	ax			;can't use bdpSrc, because editor
					; may have dirty copy of a line in it.
	mov	[psdLsIncl],si		;causes ListLine to load sdFilenameInc
	call	ListLine		; with arg to $INCLUDE
	sub	ax,ax
	mov	[psdLsIncl],ax
	cmp	[fDoIt],ax
	mov	ax,[si.SD_cb]		;ax = non-zero if $INCLUDE was found
	je	TviExit			;return if fDoIt was FALSE

	;should never be called with fDoIt true if line contains no $INCLUDE
	DbAssertRel ax,ne,0,CP,<TxtViewIncl: err2>
	push	si			;pass &sdFilenameInc
	PUSHI	ax,LF_ViewIncl		;pass file type
	inc	[fLoadInclude]		; inform LoadFile of $INCLUDE
	call	LoadFile		;ax = error code
	dec	[fLoadInclude]		; reset flag
TviExit:
cEnd

;**************************************************************
; SetCompSwitches
; Purpose:
;	Called by user interface when it is about to invoke
;	Compiler to produce an EXE file.  This function
;	scans the current text table's pcode, and sets the
;	following masks in the global static variable
;	'compSwitches' as follows:
;	  COMP_SW_E is set for each module which has ON ERROR stmt
;	  COMP_SW_X is set for each module which has RESUME [NEXT] stmt
;	  COMP_SW_V is set if any module has ON <event> stmt
;	  COMP_SW_W is set if any module has ON <event> stmt
;
; Exit:
;	ax is always non-zero (so it can be called by ForEach...)
;
;**************************************************************
cProc	SetCompSwitches,<PUBLIC,FAR>
cBegin
	call	B$GetCompSwitches	; AX nonzero if QLB used /V or /W
	or	ax,ax			
	jz	ScLoop			;brif no /V or /V in QLB
	or	[compSwitches],COMP_SW_V + COMP_SW_W ;set /V/W switches

	sub	ax,ax			;start at text offset 0
ScLoop:
	push	ax			;pass otxCur
	PUSHI	ax,<CODEOFFSET tOpCompSw>
	call	TxtFindNextOp		;ax = otx to next opcode of interest
					;dl = txtFindIndex
	cmp	dl,CSW_opEot
	je	ScExit			;brif reached opEot

	mov	bl,COMP_SW_E
	.errnz	CSW_opStOnError
	or	dl,dl
	je	ScOrMask

	mov	bl,COMP_SW_V + COMP_SW_W
	cmp	dl,CSW_EventMax
	jbe	ScOrMask		;brif ON <event>  or  <event> ON

;	If we fall through to here we have some sort of RESUME statement.
;	All variants except one require /X.  The exception is opStResume
;	with an operand other than UNDEFINED.  In this case /E is sufficient,
;	/X is overkill.  Because generated code for /E is significantly
;	smaller than /X we check for that special case here.

	mov	bl,COMP_SW_X		; assume not special case
	cmp	dl,CSW_opStResume	; found an opStResume?
	jne	ScOrMask		; no, can't be special case
	GetSegTxtTblCur 		; es = seg adr of current txt tbl
	xchg	ax,bx			; es:bx = oTx of opStResume
	cmp	word ptr es:[bx+2], UNDEFINED ; "RESUME 0" statement?
	xchg	ax,bx			; bl = /X again
	je	ScOrMask		; brif it's "RESUME 0", need /X
	mov	bl,COMP_SW_E		; got it! only need /E
ScOrMask:
	or	[compSwitches],bl
	jmp	SHORT ScLoop

;we know ax is non-zero because there is always an opEndProg before an opEot
; in every text table
ScExit:
cEnd

;**************************************************************
; ONamOVarRudeOrParse
; Purpose:
;	Get the oNam for a variable
; Entry:
;	parm1 = oNam if txdCur.scanState == SS_RUDE
;	      = oVar if txdCur.scanState == SS_PARSE
; Exit:
;	ax = variable's oNam
;
;**************************************************************
cProc	ONamOVarRudeOrParse,<FAR,PUBLIC> 
	ParmW	oNamoVar		
cBegin	ONamOVarRudeOrParse		
	mov	ax,[oNamoVar]		
	DbChk	ConStatStructs		;ensure static structures
	cmp	[txdCur.TXD_scanState],SS_RUDE
	jae	NoVarConv		; brif table is in rude-edit state
	DbChk	oVar,ax
	xchg	ax,bx			;bx is now the oVar
	add	bx,[mrsCur.MRS_bdVar.BD_pb] ;bx points to entry for variable
	mov	ax,VAR_oNam[bx] 	;fetch oNam from variable table
NoVarConv:				;ax = variable's oNam
	DbChk	oNam,ax			;pass oNam from op[A]Idxxx opcode
cEnd	ONamOVarRudeOrParse		


;--------------------------------------------------------------
; Functions which let identifiers with periods (like A.B)
; be either a scalar/array (for compatibility) or a record
; element (to support records with C-like syntax).
; In some future version of BASIC, it is conceivable that
; A.B will always mean 'element of record'.
;--------------------------------------------------------------

;**************************************************************
; ONamOfAs
; Purpose:
;	Given a pointer to an  opAsType(oNamTyp) op[A]VtRef(oNamId),
;	which is produced for syntax like 'id as user-type' in a DIM
;	type statement,	return the oNam for id.
; Entry:
;	ax = text offset into current text table to opAsType pcode
;	current text table's scan state is either SS_RUDE or SS_PARSE
; Exit:
;	carry is set if opAsType is from expression in TYPE/END TYPE block
;	else ax = oNam of id
;
;**************************************************************
ONamOfAs PROC NEAR
DbAssertRelB [txdCur.TXD_scanState],ne,SS_EXECUTE,CP,<ONamOfAs: bad scanState>
	xchg	bx,ax			;bx = text offset
	GetSegTxtTblCur			;[42]es = seg addr of current txt tbl
	cmp	WORD PTR es:[bx-4],opElemRef 
	stc				;assume we are in a TYPE block
					;note JE ONLY checks psw.z.
	je	OaExit			;brif in TYPE/END TYPE block
	
	mov	ax,es:[bx+6]		;ax = opcode following opAsType
	mov	dx,es:[bx+8]		;dx = oNam/oVar operand if scalar
.erre	opIdLd LT opVtRf		
.erre	opAIdLd GT opVtRf		
.erre	opAVtRf	GT opVtRf		
	cmp	ax,opVtRf		
	jle	OaGotONam		;brif got opVtRf or opIdLd
	mov	dx,es:[bx+10d]		;dx = oNam/oVar operand for array

OaGotONam:
	push	dx			;pass parm = oNam/oVar
	call	ONamOVarRudeOrParse 	;ax = variable's oNam
	clc
OaExit:
	ret
ONamOfAs ENDP


;**************************************************************
;ChkAsInTbl
;Purpose:
;	Checks to see if there are any refs to oNam AS in this
;	text table, for a particular oNam.  Any pcode within
;	a range which is being deleted is ignored.
;	If oNam AS is found within a TYPE block, it is ignored,
;	because type elements have their own name space.
;Entry:
;	oNamAs - oNam in question
;	oRsAs - identifies text table where text is being deleted.
;	otxAsDelStart - offset to 1st byte being deleted
;	otxAsDelEnd - offset to last byte being deleted
;Exit:
;	If oNam AS is found, returns 0
;
;**************************************************************
ChkAsInTbl PROC NEAR
	push	si			;preserve caller's si
	sub	si,si			;initial text offset = 0
CiLoop:
	push	si
	PUSHI	ax,<CODEOFFSET tOpAsType>
	call	TxtFindNextOp		;ax points to next opcode of interest
	cmp	dl,ASTYPE_opEot
	je	CiDone			;brif done with text table
	mov	si,ax			;si points to current opcode
	mov	cx,[oRsAs]
	cmp	cx,[grs.GRS_oRsCur]
	jne	CiCountIt		;brif it's not being deleted
	cmp	ax,[otxAsDelStart]
	jb	CiCountIt		;brif it's not being deleted
	cmp	ax,[otxAsDelEnd]
	jb	CiLoop			;brif it's being deleted
CiCountIt:
	cmp	dl,ASTYPE_opStDefFn
	jb	CiNotDeclare		;brif its not SUB/FUNC/DEFFN/DECLARE op

;Walk through parm list seeing if there are any oNam AS ... in parm list
	push	si			;save ptr to opStDeclare/Sub/Func
	jne	CiNotDefFn
	inc	si			;skip link field
	inc	si
CiNotDefFn:
	add	si,DCL_cParms+2		;si points to parm count field
	GETSEG	es,[txdcur.TXD_BDLTEXT_SEG] 
	lods	WORD PTR es:[si]	;ax = parm count (UNDEFINED same as 0)
	xchg	cx,ax			;cx = parm count
CiParmLoop:
	dec	cx
	js	CiParmDone		;brif done with parm list
	lods	WORD PTR es:[si]	;ax = parm's oNam/oVar
	xchg	bx,ax			;bx = parm's oNam/oVar
	lods	WORD PTR es:[si]	;ax = parm's atr flags
	xchg	dx,ax			;dx = parm's atr flags
	lods	WORD PTR es:[si]	;ax = parm's oTyp (oNam of type if rude)
	test	dx,PATR_asClause
	je	CiParmLoop		;brif parm has no AS clause
	cmp	ax,ET_MAX
	jbe	CiParmLoop		;brif ANY,INTEGER,...,STRING
	xchg	ax,bx			;ax = parm's oNam/oVar
	cmp	[txtFindIndex],ASTYPE_opStDeclare
	je	CiDeclare		;brif we're looking at DECLARE parm
					; list - no oVars, just oNams
	push	ax			;pass parm1 = oNam/oVar
	call	ONamOVarRudeOrParse	;ax = variable's oNam
CiDeclare:
	sub	ax,[oNamAs]		;see if it is id of interest
	jne	CiParmLoop		;brif not
	pop	si			;restore ptr to opStDeclare/Sub/Func
	jmp	SHORT CiDone		;return 0 - terminates ForEach...

CiParmDone:
	pop	si			;restore ptr to opStDeclare/Sub/Func
	jmp	SHORT CiLoop

CiNotDeclare:
	call	ONamOfAs		;ax = oNam of id
	jc	CiLoop			;brif AS clause was within TYPE/END TYPE
	sub	ax,[oNamAs]		;see if it is id of interest
	jne	CiLoop			;brif not
					;return 0 - terminates ForEach...
CiDone:
	pop	si			;restore caller's si
	ret
ChkAsInTbl ENDP

;**************************************************************
; ChkLastAs
; Purpose:
;	Called when opAsType op[A]Idxxx(oNam) pcode sequence is deleted.
;	If there are no other refs to oNam AS in pcode, oNam's NM_fAs
;	name table bit is reset.
;	This causes lexer to know all future references to oNam.xxx are not
;	user-type record element references.
; Entry:
;	ax = oNam
; Exit:
;	carry set if no more  <oNam> AS  constructs exist in pcode
;
;**************************************************************
PUBLIC	ChkLastAs
ChkLastAs PROC NEAR
	mov	[oRsAs],UNDEFINED
ChkLastAs ENDP
ChkLastAs1 PROC NEAR
	mov	[oNamAs],ax		;pass oNam to ChkAsInTbl
	;scan all text tables in module to see if any more AS x
	mov	bx,CPOFFSET ChkAsInTbl
	call	ForEachTxtTblInMrs
	or	ax,ax			;test return value
	je	NotLastAs		;brif found an AS x
					; exit with carry clear
	mov	bx,[oNamAs]		;pass oNam in bx
	mov	al,NM_fAS		;pass mask for bit to be reset
	call	ResetONamMask
	stc				;set return code
NotLastAs:
	ret
ChkLastAs1 ENDP

;**************************************************************
; ChkLastAsText
; Purpose:
;	Same as ChkLastAs except for input parm.
;	Pcode is assumed to be in SS_RUDE state.
; Entry:
;	ax = text offset to opAsType opcode being deleted from
;	     current text table
;	bx = text offset to 1st byte being deleted
;	cx = text offset beyond last byte being deleted
;
; Pcode is:
;  For id AS type: opAsType(oNamType) opVtRf(oNamId)
;  For id(10,20) AS type: 10,20,opAsType(oNamType) opAVtRf(2,oNamId)
;  For typeElem AS type: opElemRef(oNamElem) opAsType(oNamType)
; si is pointing to opAsType in all cases
;
;**************************************************************
cProc	ChkLastAsText,<PUBLIC,NEAR>
cBegin
	;if PreScanAsChg is active, 'AS <userType>' is not really
	;being deleted, just re-parsed, so don't reset name table bit.
	
	cmp	[fPreScanAsChg],0
	jne	ClatExit

	;save ptr to opAsType being deleted, so ChkAsInTbl doesn't
	;count one being deleted when looking for other occurances
	;of  x AS <usertype>
	
	mov	[otxAsDelStart],bx
	mov	[otxAsDelEnd],cx
	mov	dx,[grs.GRS_oRsCur]
	mov	[oRsAs],dx
	call	ONamOfAs		;ax = oNam of x for  x as <type>
	jc	ClatExit		;brif not  x as <type> pcode
	call	ChkLastAs1
	jnc	ClatExit		;brif not last  x as <type>  in pcode
	or	[mrsCur.MRS_flags],FM_asChg
					;remember to call PreScanAsChg
					; before trying to scan/run program
ClatExit:
cEnd

;**************************************************************
; PreScanAsChg
; Purpose:
;	Called just before we scan a text table in preparation
;	for execution.  Only called when text table's FM_asChg
;	bit is set, so we know that either:
;	   an 'x AS y' clause has been inserted in this table, or
;	   an 'x AS y' clause has been deleted from this table and
;	      the module contained no more 'x AS <user type>' clauses
;	It walks through every pcode in current text table.
;	For every record element x.a, if x's NM_fAs bit is not set,
;	   the line is re-parsed.
;	If the line contains an 'opNoTyp' opcode, meaning the line
;	   contains an identifier other than a record element with
;	   a period in it's name, the line is re-parsed.
;
;**************************************************************
cProc	PreScanAsChg,<PUBLIC,NEAR>,<si,di>
cBegin
	mov	[fPreScanAsChg],1
	SetStartOtx si			;si = offset to start of text table
	mov	di,si			
PsLoop:
	push	si
	PUSHI	ax,<CODEOFFSET tOpAs>
	call	TxtFindNextOp		;ax = offset to next opcode of interest
					;dl = [txtFindIndex]
	xchg	si,ax			;si = offset to opcode
	cmp	dl,AS_opNoType
	ja	PsDone			;brif got opEot
.errnz	AS_opEot - AS_opNoType - 1
	je	PsReParse		;brif opcode is opNoType
	;else opcode must be opOff...
	xchg	ax,di			;ax = ptr beyond last opOffxxx opcode
	mov	di,si			;di = ptr to current opOffxxx opcode
	add	di,4			;di = ptr beyond current opOffxxx opcode
	DbAssertRel ax,be,si,CP,<PreScanAsChg: err2>
	cmp	si,ax
	je	PsLoop			;this is just an offset modifier, like
					; c in a.b.c
	GETSEG	es,[txdCur.TXD_bdlText_seg] 
	push	es:[si-2]		;push oNam/oVar from op[A]Idxxx opcode
	call	ONamOVarRudeOrParse	;ax = variable's oNam
	push	ax			;pass oNam from op[A]Idxxx opcode
	call	FlagOfONam		;al = oNam's flags
	test	al,NM_fAS
	jne	PsLoop			;brif valid record element
	;Else, what used to look like a record element should now be a simple id
PsReParse:
	push	si			;pass opcode offset to LnOfOtx
	call	LnOfOtx			;ax = current line #
	inc	ax			;ax = line after current line
	push	ax			;pass to OtxOfLn below
	mov	ax,si			;ax = offset to opcode of interest
	call	TxtReEnter		;re list & parse line @ ax
	call	OtxOfLn			;ax = offset to next opBol/opEot
					;     (Must be done after TxtReEnter)
	xchg	si,ax			;si = offset to next opBol/opEot
	jmp	SHORT PsLoop

PsDone:
	mov	[fPreScanAsChg],0
cEnd




sEnd	CP

;**************************************************************
;      Support for GetSegAddr MACRO
;
;**************************************************************

;seg_cp = segment address for the CP segment
;It can be referenced from any module as follows:
	;	EXTRN	Seg_CP:abs
	;	mov	ax,SEG Seg_CP
	; These statements are generated by the macro call:
	;       GetSegAddr CP

	Seg_CP	=	SEG ModuleRudeEdit
	PUBLIC	Seg_CP



assumes DS,DATA 			
sEnd	CP

end

⌨️ 快捷键说明

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