📄 txtutil.asm
字号:
TITLE TXTUTIL - Text Table Management Routines
;============================================================================
;
; Module: TxtUtil.asm - Text Table Management Routines
; System: Quick BASIC Interpreter
;
; --------- --- ---- -- ---------- ----
; COPYRIGHT (C) 1985 BY MICROSOFT, INC.
; --------- --- ---- -- ---------- ----
;
;
;============================================================================
.xlist
include version.inc
TXTUTIL_ASM = ON
includeOnce architec
includeOnce context
includeOnce executor
includeOnce heap
includeOnce lister
includeOnce msgshort
includeOnce names
includeOnce optables
includeOnce opcontrl
includeOnce opid
includeOnce opmin
includeOnce opstmt
includeOnce opaftqb4
includeOnce parser
includeOnce pcode
includeOnce qbimsgs
includeOnce rtinterp ;just needed for CbStrucErrRet
includeOnce rtps
includeOnce scanner
includeOnce txtint
includeOnce txtmgr
includeOnce ui
includeOnce variable
.list
assumes DS,DATA
assumes SS,DATA
assumes ES,NOTHING
externFP B$GetCompSwitches ; runtime routine for QuickLIB switch info
;-------------------------------------------------------------------------
; DATA Segment Declarations
;-------------------------------------------------------------------------
sBegin DATA
PUBLIC fViewInclude
fViewInclude DB 0 ;non-zero if included source lines are visible
PUBLIC fLnNotIncl
fLnNotIncl DB 0 ;static return value of LnOfOtx, OtxOfLn, OtxBolOfOtx
;zero if given line was an INCLUDEd line
PUBLIC cInclNest
cInclNest DB 0 ;$INCLUDE nesting depth. Non-zero if currently loading
;an $INCLUDE file
;used to pass info to DoDescan()
descanTo DB 0
PUBLIC compSwitches
compSwitches DB 0 ;Set by SetCompSwitches()
fPreScanAsChg DB 0 ;non-zero when PreScanAsChg is active
;statics needed by ChkLastAs()
oNamAs DW 0
oRsAs DW 0
otxAsDelStart DW 0
otxAsDelEnd DW 0
externB fLoadInclude
sEnd DATA
;-------------------------------------------------------------------------
; CODE (execution-time) Segment Functions
;-------------------------------------------------------------------------
sBegin CODE
assumes CS,CODE
;Table of all the opcodes that are searched for by PreScanAsChg
;
tOpAs LABEL WORD
opTabStartAll AS
opTabEntry AS,opOffLd
opTabEntry AS,opOffSt
opTabEntry AS,opNoType ;assumed to be 2nd to last
opTabEntry AS,opEot
;Table of all opcodes which represent AS <usertype>
tOpAsType LABEL WORD
opTabStart ASTYPE
opTabEntry ASTYPE,opAsType
opTabEntry ASTYPE,opStDefFn ;must preceed Declare,Sub,Function
opTabEntry ASTYPE,opStDeclare
opTabEntry ASTYPE,opStSub
opTabEntry ASTYPE,opStFunction
opTabEntry ASTYPE,opEot
;Table of all the opcodes that are op_Include (or opStInclude [03])
;
tOpReInclude LABEL WORD
opTabStart RI
opTabEntry RI,op_Include
opTabEntry RI,opEot
;Table of all the opcodes which affect the setting of Compiler switches
;Can't use opTab... macros because we need opEot as 1st entry in table.
;
tOpCompSw LABEL WORD
opTabStart CSW
opTabEntry CSW,opStOnError
opTabEntry CSW,opEvGosub
opTabEntry CSW,opEvOff
opTabEntry CSW,opEvOn
opTabEntry CSW,opEvStop
CSW_EventMax EQU CSW_opEvStop
opTabEntry CSW,opStResume
opTabEntry CSW,opStResume0
opTabEntry CSW,opStResumeNext
opTabEntry CSW,opEot
;These functions are included in the CODE segment, because they
; are called by runtime code, and we wouldn't want to swap in
; the entire CP segment just to do these functions.
;*************************************************************************
; DescanOpcode(opcode)
;
; Purpose:
; Given the address of an executor for an opcode, return the opcode's
; id. For example, give, ExStStop, it would return opStStop.
;
; Entry:
; parm1: ushort - opcode's executor offset into CODE segment
;
; Exit:
; AX = opcode id
;
;*************************************************************************
cProc DescanOpcode,<PUBLIC,FAR,ATOMIC>
parmW opcode
cBegin
mov bx,[opcode]
mov ax,cs:[bx-2]
cEnd
sEnd CODE
;-------------------------------------------------------------------------
; CP (compile) Segment Functions
;-------------------------------------------------------------------------
; the current text table
sBegin CP
assumes CS,CP
;*************************************************************************
; TxtTblSegCurCP(), TxtSegCurCP()
;
; Purpose:
; Return the segment address for the start of the current text table.
;
; NOTE: TxtTblSegCurCP never returns the adr of the direct mode buffer.
; TxtSegCurCP return the adr of the direct mode buffer if
; grs.fDirect is TRUE.
;
; Entry:
; The structure txdCur identifies the current text table.
; For TxtSegCurCP, if grs.fDirect is TRUE, the direct mode
; text table (grs.bdlDirect) is used instead.
;
; Exit:
; TxtTblSegCurCP: ES = segment address,
; cx preserved (callers depend on this)
; TxtSegCurCP: ES = segment address
; All other registers preserved (including flags)
; (callers depend on all being preserved)
;
;*************************************************************************
PUBLIC TxtTblSegCurCP
TxtTblSegCurCP PROC NEAR
DbChk ConStatStructs ;ensure static structures
GETSEG es,[txdCur.TXD_bdlText_seg],,<SPEED,LOAD> ;[2]
ret
TxtTblSegCurCP ENDP
PUBLIC TxtSegCurCP
TxtSegCurCP PROC NEAR
pushf
push bx
DbChk TxdCur ;perform sanity check on txdCur
DbChk ConStatStructs ;ensure static structures
mov bx,dataOFFSET txdCur.TXD_bdlText
cmp [grs.GRS_fDirect],FALSE
je NotDirectMode ;branch if not in direct mode
mov bx,dataOFFSET grs.GRS_bdlDirect
NotDirectMode:
GETSEG es,[bx.BDL_seg],bx,<SPEED,LOAD> ;[2] es = seg adr of text table
pop bx
popf
ret
TxtSegCurCP ENDP
sEnd CP
sBegin SCAN
assumes CS,SCAN
;***
; TxtSegCurSCAN
;
; Purpose:
; Return the segment address for the start of the current text table.
; Added as revision [20].
;
; TxtSegCurSCAN returns the adr of the direct mode buffer if
; grs.fDirect is TRUE.
;
; Entry:
; The structure txdCur identifies the current text table.
; if grs.fDirect is TRUE, the direct mode
; text table (grs.bdlDirect) is used instead.
;
; Exit:
; TxtSegCurSCAN: ES = segment address
; All other registers preserved (including flags)
; (callers depend on all being preserved)
;
;*************************************************************************
PUBLIC TxtSegCurSCAN
TxtSegCurSCAN PROC NEAR
assumes ds,NOTHING
pushf
push bx
DbChk TxdCur ;perform sanity check on txdCur
DbChk ConStatStructs ;ensure static structures
mov bx,dataOFFSET txdCur.TXD_bdlText
cmp [grs.GRS_fDirect],FALSE
je @F ;branch if not in direct mode
mov bx,dataOFFSET grs.GRS_bdlDirect
@@:
GETSEG es,ss:[bx.BDL_seg],bx,<SPEED,LOAD> ;[2] es = seg adr of text table
pop bx
popf
ret
assumes DS,DATA
TxtSegCurSCAN ENDP
sEnd SCAN
sBegin CP
assumes CS,CP
;**************************************************************
; void DoDescan()
; Purpose:
; Called indirectly by SystemDescan and ModuleRudeEdit.
; See comments in those functions.
;
; Entry:
; descanTo = SS_PARSE or SS_RUDE
; Exit:
; grs.fDirect = FALSE
; returns ax = non-zero (so ForEach... continues)
;
;**************************************************************
DoDescan PROC NEAR
DbAssertRelB [descanTo],ne,SS_EXECUTE,CP,<DoDescan - bad descanTo>
SetfDirect al,FALSE ;turn off direct mode if on
and [grs.GRS_flags],NOT FG_allSsExecute
cmp [txdCur.TXD_scanState],SS_RUDE
jae DdExit ; brif text table is already SS_RUDE
; or lower (we never descan lower
; than SS_RUDE)
cmp [txdCur.TXD_scanState],SS_EXECUTE
jne NotExec ;we always descan at least to SS_PARSE
call SsDescan ;descan from SS_EXECUTE to SS_PARSE
DbChk TxdOps ;see if rude scanner inserted bad opcode
;Only call TxtMoved if we descanned the text table, if we call
; it every time we call DoDescan, Txt Edits slow down because we
; have lost the cache unnecessarily.
call TxtMoved ;can't depend on cached text offsets
;reset History and Watch info too
NotExec:
cmp [descanTo],SS_RUDE
jne DdExit ;brif only descanning to SS_PARSE
push WORD PTR ([descanTo]) ;pass SS_RUDE to SsRudeScan
call SsRudeScan
DbChk TxdOps ;see if rude scanner inserted bad opcode
DdExit:
mov ax,sp ;return non-zero result for ForEachCP
ret
DoDescan ENDP
;**************************************************************
; SystemDescan()
; Purpose:
; This is called to descan all module and procedure text table's
; to SS_PARSER or lower. It occurs after some edits like
; the definition of a function, to force the scanner to re-check
; all references to the function for type compatability. It
; is also called just before a Binary SAVE is executed, so we
; write opcodes to the file instead of executor addresses.
; SystemDescanRude() is identical, but all text tables are descanned
; to SS_RUDE instead of SS_PARSE.
;
; This function never results in an error (not even out-of-memory)
;
; Exit:
; grs.fDirect = FALSE
;
;**************************************************************
PUBLIC SystemDescanCP
SystemDescanCP PROC NEAR
test [flagsTm],FTM_NoSsExecute ;speed opt - skip if all
jnz SystemDescanCPX ;txt tables are already SS_PARSE
;or lower
mov al,SS_PARSE
mov [descanTo],al
;descan each prs in a module before descanning the module itself
mov al,FE_PcodeMrs+FE_CallMrsAfter+FE_PcodePrs+FE_SaveRs
mov bx,CPOFFSET DoDescan
call ForEachCP ;DoDescan returns no error codes
or [flagsTm],FTM_NoSsExecute ;all txt tables at least in
SystemDescanCPX: ;SS_PARSE scan state
SetfDirect al,FALSE ;turn off Direct mode
ret
SystemDescanCP ENDP
cProc SystemDescanRudeCP,<PUBLIC,NEAR>
cBegin
; If a def fn is active, we need to deactivate it. ForEachCP
; saves/restores oPrsCur. ModuleRudeEdit frees all def fn's.
; The combination of these two would cause ForEachCP to attempt
; to activate a freed prs if oPrsCur is for a def fn.
mov ax,[grs.GRS_oPrsCur]
inc ax ; have an active procedure?
jz NotDefFn ; brif not
dec ax
cCall FieldsOfPrs,<ax> ; returns dl = proctype
cmp dl,PT_DEFFN ; is it a def fn?
jne NotDefFn ; brif not
call PrsDeactivate ; deactivate active def fn
NotDefFn:
mov al,FE_PcodeMrs+FE_CallMrs+FE_SaveRs
mov bx,CPOFFSET ModuleRudeEdit
call ForEachCP ;ModuleRudeEdit returns no error codes
cEnd
cProc SystemDescanRude,<PUBLIC,FAR>
cBegin
call SystemDescanRudeCP
cEnd
;**************************************************************
; ModuleRudeEdit()
; Purpose:
; This is called after some edit has occurred which could have
; made existing variable tables and/or pcode inconsistent.
; For example, after a DEFINT statement is inserted in a text
; table. It descans to SS_RUDE all text tables in this module.
; It then eliminates the module's variable table (which
; holds all procedure variables for this module as well).
;
; Resets the NM_fShared name table bit and for each name table
; entry, maps NMSP_Variable to NMSP_UNDEFINED
;
; Exit:
; This function never results in an error (not even out-of-memory)
; ax = non-zero (so it can be called by ForEachCP
; grs.fDirect = FALSE
;
;**************************************************************
cProc ModuleRudeEdit,<PUBLIC,NEAR>
cBegin
test [mrsCur.MRS_flags2],FM2_NoPcode OR FM2_Include
DJMP jne NoVarTbl ;brif this mrs has no variable tables
test [mrsCur.MRS_flags],FM_AllSsRude ;speed opt - skip if all module
jnz FreeVarTbl ;text tables are already in SS_RUDE
test [txdCur.TXD_flags],FTX_mrs
je GotSubOrFunc ;brif a SUB or FUNC txt tbl is active
call PrsDeactivate ;deactivate DEF FN or DECLARE (if any)
; since DEF FNs are discarded. This
; lets us call ForEachCP with FE_SaveRs
; without crashing when we try to
; restore a discarded DEF FN.
GotSubOrFunc:
call VarDealloc ;must free all owners in module var
; table BEFORE rude descan, because
; rude descan resets the oVarHash field
; in each prs to UNDEFINED
mov [descanTo],SS_RUDE
;descan each prs in a module before descanning the module itself
mov al,FE_CallMrsAfter+FE_PcodePrs+FE_SaveRs
mov bx,CPOFFSET DoDescan
call ForEachCP ;DoDescan can return no error codes
;start of revision [39]
;Note that the below scheme depends on the fact that NextPrsInMrs
;finds the first prs in the table if grs.GRS_oPrsCur is UNDEFINED, and
;then subsequent prs's based on grs.GRS_oPrsCur. It is not safe to
;call ForEachCP to do this, because that scheme depends on walking
;the prs chain, and PrsFree causes PrsCur to be Unlinked. The next
;call ForEach pass uses the unlinked entry, and thinks that it must
;be looking at prsCur.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -