📄 txtload.asm
字号:
TITLE txtload.asm - ASCII Load Functions
;==========================================================================
;
;Module: txtload.asm - ASCII Load Functions
;System: Quick BASIC Interpreter
;
;=========================================================================*/
include version.inc
TXTLOAD_ASM = ON
includeOnce architec
includeOnce context
includeOnce conint
includeOnce fdb
includeOnce heap
includeOnce names
includeOnce opid
includeOnce opmin
includeOnce opstmt
includeOnce opaftqb4
includeOnce parser
includeOnce pcode
includeOnce qbimsgs
includeOnce rtinterp
includeOnce rtps
includeOnce rttemp
includeOnce sb
includeOnce scanner
includeOnce txtmgr
includeOnce txtint
includeOnce ui
includeOnce util
includeOnce stack2
includeOnce edit
ASC_TAB EQU 09h
ASC_LF EQU 0Ah
ASC_CR EQU 0Dh
ASC_EOF EQU 1AH
ASC_DBL_QUOTE EQU 22h
ASC_QUOTE EQU 27h
assumes DS,DATA
assumes SS,DATA
assumes ES,NOTHING
externFP B$ISTALCTMPSUB
externFP B$ISTDALCTMP
sBegin DATA
extrn b$PTRFIL:WORD ;Read only for QBI - channel Ptr
extrn szUntitled:BYTE
fInQuote DB 0
PUBLIC fMergeInSub
fMergeInSub DB 0 ;non-zero if MERGING a file into a SUB
; in this case, LoadEnterProc & LoadExitProc
; will never be called.
;temp buffers for filename before and after Normalization [7]
PUBLIC NormFname
NormFname DB FILNAML DUP (?) ;buffer for temp storage of filename
EVEN ; SD must be word-aligned!
PUBLIC sdNormFname
sdNormFname SD <0,dataOFFSET NormFname> ;string descriptor
externB b$BAS_EXT ;".bas" constant
externW b$PN_NAME
globalB fLoadInclude,0 ; Nonzero when loading include file
externB fInitialized ; non-zero if we've completed
; initialization of QB
sEnd DATA
EXTRN B$FREF:FAR
EXTRN B$OPEN:FAR
EXTRN B$IDISK_SINP:FAR
EXTRN B$CLOS:FAR
EXTRN B$SEEKSTART:FAR
EXTRN B$IDISK_BAKC:FAR
EXTRN B$IValidatePath:FAR
EXTRN B$CHAN:FAR
sBegin CODE
;Table of opcodes which make up '$STATIC, '$DYNAMIC and DEFINT
;and INCLUDE statements.
;The order of entries in this table is VERY important
;
tOpProcHdr LABEL WORD
opTabStart PROCHDR
opTabEntry PROCHDR,opStDefType
opTabEntry PROCHDR,op_Dynamic
opTabEntry PROCHDR,op_Static
opTabEntry PROCHDR,opStRem
opTabEntry PROCHDR,opQuoteRem
opTabEntry PROCHDR,opBol
PROCHDR_opBolMin equ PROCHDR_opBol
opTabEntry PROCHDR,opBolSp
opTabEntry PROCHDR,opBolInclude
opTabEntry PROCHDR,opBolIncludeSp
opTabEntry PROCHDR,opBolLab
opTabEntry PROCHDR,opBolLabSp
opTabEntry PROCHDR,opEndProg
;must be 2nd to last entry in table
opTabEntry PROCHDR,opEot
;must be last entry in table
sEnd CODE
sBegin DATA
;-------------------------------------------------------------------
; During ASCII Load/Merge, we don't update threaded linked lists
; through the pcode for each line, because it is very slow.
; Much faster to update them all at once when we're done.
; This must be done at the following points:
;
; 1 - when we enter a procedure, since we are moving into
; a new text table.
; 2 - when we exit a procedure, since we are returning to
; the module's text table.
; 3 - When the Load reaches end-of-file
;
; otxUpdLinks represents an offset into the current text table to the
; 1st byte of pcode which UpdateLinks() has not been called for yet.
;
;-------------------------------------------------------------------
EXTRN tabStops:WORD ;defined in edit manager
PUBLIC otxUpdLinks
otxUpdLinks DW 0
;fDynArrays is initialized to FALSE by AsciiMerge, set TRUE when $DYNAMIC is
;seen by TxtChange, set FALSE when $STATIC is seen by TxtChange
;
PUBLIC fDynArrays
fDynArrays DB 0
;fDynArraysMod is set to the value of fDynArrays when we enter a procedure
; (LoadEnterProc), so we can restore the $DYNAMIC/$STATIC state when we
; return back to module level (LoadExitProc).
;
fDynArraysMod DB 0
;fProcDyn is TRUE if a $DYNAMIC deleted later than a $STATIC,
;i.e. the state at the end of the deleted range was $DYNAMIC
;and not $STATIC.
;
PUBLIC fProcDyn
fProcDyn DB 0
;otxLastProc = text offset in module's text table where we were
;when we entered the most recent SUB/FUNCTION. One way to think
;of it is, when were in a procedure, its the module's text offset
;where the 1st line after the END SUB/FUNCTION will be inserted
;into the module's text table.
;
otxLastProc DW 0
;otxNewInsert is initialized to UNDEFINED by AsciiMerge,
;and set by LoadEnterProc and LoadExitProc to tell AsciiMerge
;that we switched text tables
;
otxNewInsert DW 0
;cbAftMerge is initialized to 0 by LoadFile,
;if we're doing anything except a MERGE. If we're doing a MERGE,
;it marks the insertion point in the main module.
;
cbAftMerge DW 0
;otxDefStart and otxDefEnd represent the range of text in the module's
;text table for DEFtype statements synthetically emitted by LoadExitProc.
;If, when the Load completes, this range is at the end of the module,
;it is discarded. If we didn't do this, the module would grow with
;every subsequent LOAD/SAVE
;
otxDefStart DW 0
otxDefEnd DW 0
;used to keep procedure DEFtype stmts independent of module's DEFtype statements
;
PUBLIC tEtTemp
tEtTemp DB 26 DUP(0)
PUBLIC chanCur
chanCur DW 0 ;current channel # used by Load/Save
PUBLIC cChansOpen ;only referenced by FLoadActive macro
cChansOpen DB 0 ;number of recursive calls to LoadFile active, bumped
; every time file is opened, decremented when closed.
cAsciiLoadsActive DB 0 ;number of recursive calls to LoadFile active for
; ASCII files
sEnd DATA
;---------------------------------------
; SUB/FUNCTION Window Support Functions
;---------------------------------------
externFP FindFile
sBegin CP
assumes cs,CP
;*************************************************************
; boolean NEAR InsertEtDiff(ax:otxInsert, ptEtBase, ptEtNew)
; Purpose:
; Emit opBol and opStDefType statements necessary to move from
; one set of default-types to another.
; The new pcode is emitted at otxInsert in the current module.
;
; NOTE: This routine doesn't update the line count for any inserted BOLs.
; The caller is responsible for updating the line count if it is
; needed.
;
; Entry:
; ax:otxInsert = offset into current module's text table where
; synthetic pcode is to be emitted.
; ptEtBase and ptEtNew point to an arrays of 26 bytes, one ET_xx for each
; letter from A to Z.
;
; Exit:
; If ptEtBase is identical to ptEtNew, no pcode is emitted.
; else the pcode emitted is the most efficient way to get from
; ptEtBase to ptEtNew.
; If out-of-memory, returns ax = 0 (and psw.z set)
; else returns ax non-zero
;
;*************************************************************
DEFLN STRUC
DEFLN_bolOpcode DW 0
DEFLN_defOpcode DW 0
DEFLN_defLinkField DW 0
DEFLN_defOperandLO DW 0
DEFLN_defOperandHI DW 0
DEFLN ENDS
cProc InsertEtDiff,<PUBLIC,NEAR>,<si,di>
parmW ptEtBase
parmW ptEtNew
localV deflnNew,<SIZE DEFLN>
cBegin
xchg di,ax ;di = insertion point (otxInsert)
mov [deflnNew.DEFLN_bolOpcode],opBol
mov [deflnNew.DEFLN_defOpcode],opStDefType
mov si,CBASETYPEMAX ;init etCur
InsEtLoop:
dec si ;decrement etCur
js InsEtEnd ;brif we've done all primitive types
push [ptEtBase]
push [ptEtNew]
push si ;pass etCur
call EtDiff ;[dx:ax] = bit mask representing
; difference between base and new type
; with respect to si (etCur)
mov [deflnNew.DEFLN_defOperandLO],ax
mov [deflnNew.DEFLN_defOperandHI],dx
or ax,dx
je InsEtLoop ;brif no difference between base & new
push di ;pass otxInsert
PUSHI ax,<SIZE DEFLN>
call TxtMoveUp ;make room for pcode to be inserted
je InsEtExit ;return FALSE if out-of-memory
;insert new pcode in current text table
PUSHI ax,<dataOFFSET txdCur.TXD_bdlText>
push di ;pass otxInsert
lea ax,[deflnNew]
push ax
PUSHI ax,<SIZE DEFLN>
call BdlCopyTo
jmp SHORT InsEtLoop
InsEtEnd:
mov ax,sp ;return TRUE (non-zero)
InsEtExit:
or ax,ax ;set condition codes for caller
cEnd
;*************************************************************
; boolean InsertDynDiff(ax:otxInsert, dh:fDynBase, dl:fDynNew)
; Purpose:
; Emit pcode for REM $STATIC or REM $DYNAMIC if fDynBase <> fDynNew.
; The new pcode is emitted at otxInsert in the current module.
;
; NOTE: This routine doesn't update the line count for any inserted BOLs.
; The caller is responsible for updating the line count if it is
; needed.
;
; Entry:
; ax = otxInsert = offset into current module's text table where
; synthetic pcode is to be emitted.
; dh = fDynBase = 1 if we were already in $DYNAMIC mode.
; dl = fDynNew = TRUE if we want to move into $DYNAMIC mode.
; Exit:
; ax = 0 if out-of-memory error (psw.z set as well)
;
;*************************************************************
PUBLIC InsertDynDiff
InsertDynDiff PROC NEAR
push si ;save caller's si,di
push di
xchg di,ax ;di = text offset where pcode is to go
cmp dh,dl
je InsDynGoodExit ;brif we're already in mode we want
mov si,op_Static
or dl,dl
je ItsStatic ;brif new state is $STATIC
mov si,op_Dynamic
ItsStatic:
;insert the pcode into text table in reverse order
push di ;push source of move to TxtMoveUp
PUSHI ax,10d ;push number of bytes to insert
call TxtMoveUp
or ax,ax
je InsDynExit ;return FALSE if out-of-memory
GetSegTxtTblCur es ;es = seg adr of heap entry for txt tb
mov ax,opBol
stosw ;insert beginning-of-line opcode
mov ax,opStRem
stosw ;insert REM opcode
sub ax,ax
stosw ;insert rem's cb operand
mov ax,si ;ax = op_Static or op_Dynamic
stosw
sub ax,ax
stosw ;insert op_Dynamic/op_Static's operand
InsDynGoodExit:
mov ax,sp ;return TRUE (non-zero)
InsDynExit:
pop di ;restore caller's si,di
pop si
or ax,ax ;set condition codes for caller
ret
InsertDynDiff ENDP
;*************************************************************
; void SqueezeDefs(si:otxCur)
; Purpose:
; Squeeze out all opStDefType, op_Dynamic and op_Static opcodes
; from otxCur to the end of the current text table.
; We squeeze them out and synthetically generate new ones
; to eliminate redundant statements which could be introduced
; as a result of moving SUBs and FUNCTIONs to their own text tables
; during ASCII load.
; Entry:
; si = text offset where we are to start deleting opcodes
; Exit:
; The static variable [fProcDyn] is TRUE if a $DYNAMIC deleted
; later than a $STATIC, i.e. the state at the end of the deleted
; range was $DYNAMIC and not $STATIC.
;
;*************************************************************
cProc SqueezeDefs,<PUBLIC,NEAR>,<si,di>
localW otxLastBol
localB fDeleted
localB opIndex
cBegin
sub ax,ax
mov [fProcDyn],al ;default state is $STATIC
mov [fDeleted],al ;so far we've deleted nothing
dec ax ;ax = UNDEFINED
mov [otxLastBol],ax
push si ;pass otxCur
PUSHI ax,<CODEOFFSET tOpProcHdr>
call TxtFindOp ;ax = text offset to 1st found opcode
;dl = [txtFindIndex]
cmp dl,PROCHDR_opEot
jb NotEot
jmp SqExit ;brif end of table
NotEot:
xchg si,ax ;update si = otxCur
cmp dl,PROCHDR_opBolMin
jb SqLoop ;brif not opBol or opBolSp
mov [otxLastBol],si ;save offset to last start of line
;NOTE that TxtFindNextOp(x, p) sets txtFindIndex but
;TxtSkipOp() does not
;dl = txtFindIndex from last call to TxtFind[Next]Op
;
SqLoop:
mov [opIndex],dl ;save opcode's id (PROCHDR_xxx)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -