📄 txtdir.asm
字号:
TITLE txtdir.asm - Text Mgr's Direct Mode Statement support
;==========================================================================
;
;Module: txtdir.asm - Text Mgr's Direct Mode Statement support
;System: Quick BASIC Interpreter
;
;=========================================================================*/
;
; How a direct-mode statement gets executed
;
; User-Interface
; / |
; TxtDirect |
; | \ |
; +--------------+ \ |
; | | \ |
; | ParseLine SystemScan
; | |
; | ForEach...
; | |
; | +---------------+
; | | |
; +-----+-+ ScanTxtTbl ReParseTbl
; | | |
; | +----)---+
; | | | |
; SsRudeScan SsScan
;
;
; User-Interface calls SystemScan for Single-Step, in case user edited
; program between single steps. It also calls SystemScan for the
; Compile... menu, so we don't try to compile a program with errors.
; TxtDirect calls ParseLine, SsRudeScan and SsScan for the direct
; mode statement.
; ReParseTbl calls DoReParse for any statements not yet accepted
; by the parser, then ScanTypeBlocks, so variable manager knows
; about all TYPE/END TYPE blocks.
; ScanTxtTbl then calls SsRudeScan (if necessary) and SsScan (if necessary)
; to get the text table ready to execute.
; Some direct mode statements (like SYSTEM) don't require all loaded pcode
; to be scanned. In these cases, TxtDirect never calls SystemScan.
;
;=========================================================================*/
.xlist
include version.inc
TXTDIR_ASM = ON
includeOnce architec
includeOnce context
includeOnce lister
includeOnce opcontrl
includeOnce opid
includeOnce opmin
includeOnce opstmt
IncludeOnce opaftqb4
includeOnce parser
includeOnce pcode
includeOnce qbimsgs
includeOnce rtinterp
includeOnce scanner
includeOnce txtint
includeOnce txtmgr
includeOnce ui
.list
assumes DS,DATA
assumes SS,DATA
assumes ES,NOTHING
sBegin DATA
scanTo DB 0 ;used by ScanTxtTbl
sEnd DATA
sBegin CODE
;These opcodes are of special interest whenever they appear in direct mode:
;
tOpDirect LABEL WORD
opTabStartAll DIR
;list of opcodes which are illegal in direct mode
;many more illegal stmts are caught by NtStatement()
opTabEntry DIR,opBolLab
opTabEntry DIR,opBolLabSp
opTabEntry DIR,opBolInclude
opTabEntry DIR,opBolIncludeSp
opTabEntry DIR,op_Static
opTabEntry DIR,op_Dynamic
opTabEntry DIR,op_Include
opTabEntry DIR,opStData
opTabEntry DIR,opStDefFn
opTabEntry DIR,opStEndDef
opTabEntry DIR,opStEndIfBlock
opTabEntry DIR,opStEndProc
opTabEntry DIR,opStEndType
DIR_ILLEGAL EQU DIR_opStEndType
;All opcodes until end of list cause entire program to be scanned
;list of opcodes which have direct mode variants
opTabEntry DIR,opStGosub
opTabEntry DIR,opStGoto
opTabEntry DIR,opStElseLab
opTabEntry DIR,opStIfLab
DIR_DM_VARIANT EQU DIR_opStIfLab
;list of opcodes which cause entire program to be scanned & CantCont
opTabEntry DIR,opStRunLabel
opTabEntry DIR,opStRunMain
DIR_CANTCONT EQU DIR_opStRunMain
opTabEntry DIR,opStChain
opTabEntry DIR,opStCallS
opTabEntry DIR,opStCall
opTabEntry DIR,opStCallLess
opTabEntry DIR,opStRead
opTabEntry DIR,opStResume0
opTabEntry DIR,opStResumeNext
opTabEntry DIR,opStReturn0
opTabEntry DIR,opEot
sEnd CODE
sBegin CP
assumes cs,CP
;--------------------------------
; TxtDirect and support functions
;--------------------------------
;**************************************************************
; boolean ScanTxtTbl()
; Purpose:
; Called by SystemScan via ForEachTxtTbl(ScanTxtTbl).
;
; Make sure all SUBs and FUNCTIONs are defined and terminated.
; Note this isn't called for DEF FNs. Any change to a DEF FN
; causes a RUDE descan, so rude-scanner is responsible for
; making sure all DEF FNs are terminated.
;
; If the text table's scan-state > [scanTo],
; First, it makes sure all TYPE/END types have been made known to
; the variable manager.
; Then it traverses the text table's ReParse linked list,
; calling TxtChange() for each line.
; Then it calls SsRudeScan(SS_PARSE) to scan the text table to SS_PARSE
; or SsScan() to scan the text table to SS_EXECUTE
;
; Entry:
; grs.fDirect = FALSE
; Text table to be scanned has been loaded by context mgr.
;
; Exit:
; ps.bdpSrc (parser's input buffer) is used.
; If no errors were encountered by either TxtChange or SsScan,
; return value is TRUE (so ForEach... will continue)
; else
; return value is FALSE,
; it is caller's responsibility to set grs.fDirect = FALSE
; txtErr.errCode = an offset into the QBI Message Table (MSG_xxx) or,
; if high-bit set, ps.bdpError contains the parser-built
; ASCII error message,
; txtErr.fDirect is set to FALSE,
; txtErr.oRs identifies the text table with the error,
; txtErr.otx contains the offset into the text table to the offending
; source line (otxDelFirst).
; txtErr.oSrcErr contains the column offset into the source line
; to the offending token.
;
;Alters:
; ps.bdpSrc (parser's source buffer)
;
;**************************************************************
DbPub ScanTxtTbl
cProc ScanTxtTbl,<NEAR>
cBegin
test txdCur.TXD_flags,FTX_mrs
jne ScanTxt ;brif not a SUB/FUNCTION text table
test [prsCur.PRS_flags],FP_DEFINED
je ScnSubErr ;brif proc does not have a SUB/FUNC
test [prsCur.PRS_flags],FP_ENDPROC
jne ScanTxt ;brif proc has END DEF/SUB/FUNCTION
;error - this SUB/FUNCTION has no END SUB/FUNCTION
mov ax,MSG_ProcNoEnd ;SUB/FUNCTION/DEF without END SUB/F...
mov dx,[prsCur.PRS_otxDef]
jmp short ScnSubErrCom
ScnSubErr:
;Give "Statement cannot precede SUB/FUNCTION definition" error
mov ax,MSG_InvBeforeProcDef ;ax = error code
sub dx,dx ;text offset of error = 0
ScnSubErrCom:
mov [txtErr.TXER_oSrc],0
DJMP jmp SHORT ScanErrCommon
ScanTxt:
test [mrsCur.MRS_flags3],FM3_NotFound
je FileLoaded
;The user loaded a .MAK file which named this module, but
;the module could not be found.
mov [grs.GRS_otxCur],0
mov ax,[grs.GRS_oMrsCur]
call SetPsErrMsg ;set ps.bdErr to name of module
;if static err buf, OM err not possible
mov ax,ER_OM
DJMP je ScanErr ;brif out-of-memory
mov ax,MSG_MrsNotFound
; 'Module not found. Unload from program? <OK/Cancel>.
; ReportError() will Unload mrs if OK and MSG_MrsNotFound.
DJMP jmp SHORT ScanErr
FileLoaded:
and [mrsCur.MRS_flags],NOT FM_AllSsRude ;we have at least one non
;SS_RUDE text table in this module.
mov al,[scanTo] ;al = desired state
cmp al,[txdCur.TXD_scanState]
DJMP jae SctGoodExit ;brif this table is already scanned
; to at least [scanTo]
;***** Start Revision [41]
;***** End Revision [41]
STT_DoScan:
cmp al,SS_EXECUTE
je ToExecute ;brif scanning to SS_EXECUTE
PUSHI ax,SS_PARSE ;pass target state to SsRudeScan
call SsRudeScan ;scan to SS_PARSE
or ax,ax
jz SctGoodExit ; brif no error
;ax = error code
jmp SHORT ScanErr
;Scan current text table from SS_PARSE to SS_EXECUTE
ToExecute:
call SsScan ;scan text table to SS_EXECUTE
;ax = scanner error (0 if none)
;grs.otxCur = location of error
DbChk TxdOps ;see if scanner inserted bad opcode
or ax,ax
jne ScanErr ;brif scanner encountered errors
and [flagsTm],NOT FTM_NoSsExecute ;we now have a table in
;SS_EXECUTE
SctGoodExit:
mov ax,UNDEFINED ;double duty - - - non-zero == TRUE
cmp [grs.GRS_otxCONT],ax
jnz SctExit ;brif can CONTinue
call ResetData ;ensure the next READ is to the
; first DATA stmt in this module
; this is needed only for READ in
; direct mode buffer after we set
; Cant CONTinue.
;AX already set non-Zero by call to ResetData
SctExit:
or ax,ax
cEnd
;ax = error code, grs.otxCur = text offset to error
ScanErr:
mov dx,[grs.GRS_otxCur] ;dx = otx of reported error
mov [txtErr.TXER_oSrc],UNDEFINED
;for scanner detected errors, we cant
;detect the column, compute from otx
;ax = error code, dx = text offset to error
ScanErrCommon:
mov [txtErr.TXER_errCode],ax
cmp dx,UNDEFINED
je SetOtx ;brif otx of error is UNDEFINED
;Scanner sometimes leaves grs.otxCur pointing within an opcode
;Force it to an opcode boundary for accurate error reporting.
;Scanner sets low bit of otx if the otx points to an oVar
;within an opStDeclare opcode.
mov bx,dx ;bx = dx = otx of err
and dl,0FEh ;turn off low bit
cmp bx,dx
jne SetOtx ;brif error was within opStDeclare
sub ax,ax ;tell TxtSkipOp to start at StartOTx
SeOtxLoop:
push bx ;save otxErr
push ax ;save otxPrev
cCall TxtSkipOp ;ax = otx to next opcode after ax
pop dx ;dx = otxPrev
pop bx ;bx = otxErr
cmp ax,bx
jbe SeOtxLoop ;brif current opcode's otx <= otxErr
SetOtx:
mov [txtErr.TXER_otx],dx ;save real text offset to error
mov ax,[grs.GRS_oRsCur]
mov [txtErr.TXER_oRs],ax
mov al,[grs.GRS_fDirect]
mov [txtErr.TXER_fDirect],al
call ChkWatchErr ;modify txtErr if error in Watch expr
;txtErr.otx = text offset of error
;txtErr.oSrc = column of error
;txtErr.errCode = error code
sub ax,ax ;return FALSE
jmp SHORT SctExit
;**************************************************************
; boolean SystemScan
; Purpose:
; Scan all text tables to SS_EXECUTE
; Exit:
; if any scanner or reparse errors were encountered:
; txtErr.errCode = an offset into the QBI Message Table (MSG_xxx) or,
; if high-bit set, ps.bdpError contains the parser-built
; ASCII error message,
; txtErr.fDirect is FALSE,
; txtErr.oRs identifies the text table with the error,
; txtErr.otx is an offset into the text table where the error
; was detected.
; txtErr.oSrc identifies the column within the source line where
; the error was detected.
; else
; txterr.errCode = 0
; condition codes set based on value in txterr.errCode == 0
;
;**************************************************************
cProc SystemScan,<PUBLIC,FAR>
cBegin
mov [txtErr.TXER_errCode],0 ;assume no errors
test [grs.GRS_flags],FG_allSsExecute
jnz SsExit
NotDone:
SetfDirect al,FALSE ;tells scanner, parser we're not
;scanning direct mode stmt,
;if we find any errors, they won't be
;in the direct mode buffer
;See if user entered/loaded a $INCLUDE <filename> statement
; and the file was not found, or saved an Include file.
;If so, re-evaluate all $INCLUDE statements in all text tables.
call NotSavedInc ;save all unsaved INCLUDE files
or ax,ax
; if files saved ok, ax=0
; if no need to save any, ax=-1
; if CANCEL, ax=MSG_GoDirect
; if NO, ax=-2
; if I/O error, ax = error code
jg SsError ; brif I/O error or cancel
inc ax ;test for -1
je SsNoSave ;brif no files needed to be saved
jl SsCancel ;brif user decided not to save
; one or more INCLUDE files
SsNoSave:
call TxtReInclude ;re-parse all $INCLUDE lines if
; any INCLUDE mrs's have been saved
or ax,ax ;ax = txtErr.errCode
jne SsDone ;brif error (errors like FileNotFound
; would not get caught in ReParse loop)
call TxtMoved ;remember pcode has moved
mov ax,-MSG_Compiling ;display Loading msg in intense video
call StatusMsgCP ; to tell user we're compiling
;First make sure all DEFFNs/SUBs/FUNCTIONs are defined and terminated
mov al,FE_PcodeMrs+FE_CallMrs+FE_SaveRs
mov bx,CPOFFSET ReParseTbl
call ForEachCP ;re-parse until no more opReParse
; opcodes in the system.
je SsDone ;brif error
xor ax,ax
mov [SsLineCount],ax
cCall UpdStatusLn,<ax>
;Next, scan all text tables to SS_PARSE state
mov [scanTo],SS_PARSE
mov bx,CPOFFSET ScanTxtTbl
call ForEachTxtTbl
je SsDone ;brif error
mov [SsLineCount],0
;Next, scan all text tables to SS_EXECUTE state
;If we didn't do it in this order, it would be possible to
;scan one text table to SS_EXECUTE, which contained references
;to a function in another text table which was still in SS_RUDE
;state. This would be trouble, because the function's return
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -