📄 excontxt.asm
字号:
page 49,132
TITLE EXCONTXT - context-related executors
;***
;excontxt.asm - context-related executors
;
; Copyright <C> 1986, Microsoft Corporation
;
;Purpose:
;
;
;Special Information regarding [re]initialization:
; - This module contains the fundamental entry point to which
; 1-time initialization branches.
; - When UserInterface() is called, this represents a major transfer
; of control; the User Interface takes over. It saves away the
; keyboard interrupt handler that the runtime installed at
; 1-time initialization, and restores it prior to returning here.
; Within the User Interface (UI), ES is no longer preserved, and
; one may not assume that SI or DI represent anything in particular.
; - Some executors in this module will behave differently in our
; full shell version than in the "Runtime Module" version, i.e.,
; the version which can just binary load QBI programs and run them.
; Executors which terminate execution are at the head of this list
; rather than returning to the shell, in the Runtime Module version,
; these will cause QBI to terminate and exit to DOS.
; - Note that anyone that changes grs.fDirect sets up a 'critical
; section' situation: if a runtime error occurs after grs.fDirect
; has been changed, and grs.oTxCur is not pointing to some exBol/Bos
; opcode in the text table owned by txdCur, runtime error handling
; will go out to lunch.
; - The way we allow for RUN <filename> and CHAIN to load a file and
; get it scanned is to have them call LoadFile, then put an actual
; executor address in the direct mode buffer, set a bit in debugFlags,
; and just dispatch. We know that the following BOS/BOL/EOT will cause
; UserInterface() to regain control; UserInterface() will see the
; debugFlags bit set, and cause the direct mode buffer to be executed.
;
;****************************************************************************
.xlist
include version.inc
EXCONTXT_ASM = ON
IncludeOnce architec
IncludeOnce conint
IncludeOnce context
IncludeOnce executor
IncludeOnce exint
IncludeOnce extort
IncludeOnce opcontrl
IncludeOnce opmin
IncludeOnce opstmt
IncludeOnce qbimsgs
IncludeOnce rtinterp
IncludeOnce rtps
IncludeOnce rttemp
IncludeOnce scanner
IncludeOnce txtmgr
IncludeOnce ui
IncludeOnce variable
.list
assumes DS, DATA
assumes es, NOTHING
assumes ss, DATA
sBegin DATA
externW b$cCSubs ;count of compiled BASIC frames on stack
externB b$inonerr ;used to check for No RESUME error @ implied END
externW b$errnum
externW b$ErrInfo ;extended error codes (UI <--> Runtime)
externB fInitialized ;non-zero if we've completed initialization of
; quick basic
externB b$CtrlFlags ;byte of runtime-specific flag bits
staticW oTxRunSave,0 ;!#@$ static location to save oTxCur before
;RunFile or CHAIN.
sEnd DATA
EXTRN B$IEND:FAR
EXTRN B$IEndSt:FAR
EXTRN B$SCLR:FAR
EXTRN B$ClearRange:FAR
EXTRN B$STACKINIT:FAR
EXTRN RtError_INI:FAR
EXTRN fEditorActive:FAR
sBegin CODE
assumes cs, CODE
EXTRN DoFBosResetStk:near
extrn I4ToU2:near
;***
;exStop, exStEnd, exStSystem - STOP, END, & SYSTEM Statement Executors
;
; Note that, for STOP, UserInterface will save the CONTinue context
; we don't have to do that here.
;
; Note that for compiled BASIC STOP and END/SYSTEM, the runtime
; will do a jump to B$IStop or exStEnd.
;
; Note that SI, DI, & ES may not be correctly set on entry to B$IStop.
;
;***************************************************************************
PUBLIC B$IStop ;runtime call-back if ctrl-Break is
B$IStop: ; seen, or compiled Basic STOP stmt
mov al,[grs.GRS_fDirect]
or al,al ; in direct mode window?
jnz SkipCursorStuff ; yes, skip cursor positioning
push ax ; save direct mode flag because
; OtxBosOfOtx hoses fDirect
call EnStaticStructs ;bring txdCur up to date
push [grs.GRS_otxCur] ;parm to OtxBosOfOtx
call OtxBosOfOtx ;ax = oTx of BOS/BOL of current stmt
;we do this so we don't try to continue
;execution in the middle of a statement
xchg ax, bx ; bx = otx of pcode to skip.
call TxtSkipOpFar ;ax = oTx of pcode following BOS/BOL.
; we do this so txtmgr can tell for
; sure which line to put the cursor on
xchg ax,si
pop ax
mov [grs.GRS_fDirect],al ;in case OtxBosOfOtx changed fDirect
call DisStaticStructs
SkipCursorStuff:
and [BosFlags],NOT FBOSSTOP
mov bp,[b$curframe]
SkipExHeader
MakeExe exStStop,opStStop
or [debugFlags],DEBUG_STOP ;indicate program stopped
cmp [fNonQBI_Active],FALSE ;was QBI code active when we stopped?
jz StopGrsContext ;brif so
;We were stopped in QuickLib code. We cannot CONTinue, but we
;do want to be able to allow the user to print variables, and stack
;trace from the most recent QBI frame back.
or [debugFlags],DEBUG_CANT_CONT
call ResetSP_BP_Far ; reset SP & BP based as appropriate
; depending on whether QBI code
; was active or not.
mov sp,ax ;set SP based on retval
jmp SHORT StopGrsContext
MakeExe exStSystem,opStSystem
test [cmdSwitches],CMD_SW_RUN ;/Z filename given on command line?
jnz Exit_Basic ; brif so - - always exit
cmp [grs.GRS_fDirect],FALSE ;in Direct Mode?
jz exStEnd ; brif not - - act just like END stmt
Exit_Basic:
or [debugFlags],DEBUG_END ; indicate end-of-program, to ensure
; error not trappable in case of
; I/O error
cCall NotSaved ;notify user, get his response.
; if CANCEL, ax=MSG_GoDirect
; if user said NO, ax=FFFF
; if I/O error, ax = error code
; if files saved ok, ax=0
jg J2_RtErrorCODE ;brif runtime error while
; saving files, or CANCEL
call B$IEND ;tell runtime to terminate - - never
; returns
MakeExe exStEnd,opStEnd
or [debugFlags],DEBUG_CANT_CONT
;make sure UserInterface() doesn't
; let us continue execution
mov [grs.GRS_otxCur],si ; in case of error in closing files
or [debugFlags],DEBUG_END ; indicate end-of-program, to ensure
; errors aren't trappable
call B$IEndSt ;close all user files
SkipExHeader ;fall through except for closing files,
; exEndProg is an implied END executor
;***
;exEot, exEndProg - End of Program Executor
;Purpose:
; exEndProg is the main interpreter loop control. It calls the
; front end to obtain work. It then executes the current text
; table. All text tables contain an exEndProg after the user's pcode.
; The loop is completed by execution of the exEndProg at the end of some
; text table.
;
;***************************************************************************
MakeExe exEot,opEot
SkipExHeader
MakeExe exEndProg,opEndProg
cmp [b$inonerr],FALSE
jz EndProg1 ;brif not in an error trap
cmp [grs.GRS_fDirect],FALSE
jnz EndProg1 ;brif EOT in Direct Mode buffer
mov al,ER_NR ;No RESUME error
J2_RtErrorCODE:
call RtErrorCODE ;runtime error - doesn't return
EndProg1:
;if something like NEW happened as the last statement, the stack won't
; have been cleared yet (and who knows, we might have something
; meaningful on the stack when we hit our next BOS/BOL after
; UserInterface(?)
test [BosFlags],FBOSRESETSTK
jz Ep_Cont
call DoFBosResetStk ;reset the stack
Ep_Cont:
or [debugFlags],DEBUG_END ;indicate end-of-program
mov si,UNDEFINED ;Save context (end of program)
;fall into StopGrsContext
PUBLIC StopGrsContext
StopGrsContext:
mov [grs.GRS_otxCur],si ;Save text pointer
mov [b$curframe],bp ;required by RT error handling code
DbChk BpChain ;ensure the bp chain is walkable
DbAssertRel sp,a,b$pendchk,CODE,<StopGrsContext: SP below b$pendchk>
;ensure sufficient stack space for U.I.
cmp [b$errnum],ER_OM
jz Enter_UI ;brif might already be short on space
call GrabSpace ;ensure there's enough free space to
; at LEAST do a CLEAR ...
or ax,ax
jnz Enter_UI ;brif allocations successful
OM_Err:
mov al,ER_OM ;don't enter UI if we can't even
jmp J2_RtErrorCODE ; get enough space to do a CLEAR - -
Enter_UI:
call ReleaseSpace ;release special space allocated by
; GrabSpace
call EnStaticStructs ;activate static prsCur, mrsCur, txdCur
test [debugFlags],DEBUG_ERROR OR DEBUG_STOP OR DEBUG_END
jz Enter_UI_1 ;brif not going back into UI to stay
; a while ...
call FreeAllUnrefdPrs ;Remove any prs's that arn't ref'd
; anywhere AND that don't have text
; tables. This is needed in case
; the user called a prs in a QuickLib
; from direct mode, and this was the
; only reference to the prs.
Enter_UI_1:
mov bx,dataOFFSET prsCur
test byte ptr [grs.GRS_oRsCur+1],080H
jnz PrsIsActive
mov bx,dataOFFSET mrsCur
PrsIsActive:
.errnz MRS_cbFrameTemp - PRS_cbFrameTemp
mov ax,[bx.MRS_cbFrameVars]
push ax ;save in case more vars added to frame
add ax,[bx.MRS_cbFrameTemp]
push ax ;save in case frame size grows
DbMessTimer CODE,<Enter UserInterface() - >
cCall UserInterface ;Call direct mode for more work
DbMessTimer CODE,<Leave UserInterface() - >
cmp [grs.GRS_fDirect],FALSE
jnz No_Stk_Reinit ; brif Direct mode
mov bx,sp ;reset empty words in stack for FRE(-2).
sub bx,4 ;so cbFrameVars and cbFrame on stack
; arn't hosed ...
call B$STACKINIT ;Must do this here as UserInterface
; is called one last time AFTER RunInit
No_Stk_Reinit:
pop si ;previous frame size for oRsCur
pop di ;previous cbFrameVars for oRsCur
;(popping this here, as B$STACKINIT
; trashes di ... pfthhhhhhhhhhp!)
xor bx,bx
mov [fNonQBI_Active],bx ;ensure this flag is reset
cmp [grs.GRS_otxCONT],UNDEFINED
jnz GetpRsCur ;brif can CONT
;we must set SP based on BP so direct mode statments have the
;required amount of temp and var space on the frame. Prior to
;doing this, however, we must release any owners on the stack - - -
;we can't wait for the first BOS/BOL to occur, because resetting
;sp means that we could overwrite an owner ...
cmp [grs.GRS_fDirect],FALSE ;executing in the direct mode buffer?
jz GoStartGrsContext ; brif not - - - can't be any owners
; that we could hose here, and parms
; from Direct Mode CALL must not be
; released (example: call foo("bar")
; from direct mode)
push [b$pend] ;lomem of range to clear
push [b$mainframe] ;himem of range to clear
call B$ClearRange ;release any owners in given range
GoStartGrsContext: ; got relative jump out of range
jmp short StartGrsContext
GetpRsCur:
mov bx,dataOFFSET prsCur
test byte ptr [grs.GRS_oRsCur+1],080H
jnz PrsIsActive1
mov bx,dataOFFSET mrsCur
PrsIsActive1:
push ds ;for later rep mov's and/or sto's
pop es
cmp [pGosubLast],0 ;active pGosubLast chain?
jz Check_FrameVar_Size ; brif not
cmp bp,[pGosubLast] ; is the chain in this proc?
jb Check_FrameVar_Size ; no, then it's sure not active!
.errnz MRS_cbFrameVars - PRS_cbFrameVars
.errnz MRS_cbFrameTemp - PRS_cbFrameTemp
mov ax,[bx.MRS_cbFrameVars]
add ax,[bx.MRS_cbFrameTemp]
mov dx,ax
sub dx,si
jbe Check_FrameVar_Size ;brif sufficient frame space exists
;Frame size has been increased; must move all gosub frames down to
;account for the difference
;Do this in two steps:
; (1) update pGosubLast chain to account for movement
; (2) move all gosub frames down.
;Note that there can be an event gosub frame here, but if so, it
; has to be the active mrs frame - - - we can treat this the
; same way.
push di
mov di,[pGosubLast]
Update_Gosub_Ptrs: ;loop for step (1)
mov cx,[di] ;fetch ptr to next frame
jcxz Move_Gosub_Frames ;brif no more gosub frames
sub [di],dx ;update current frame ptr by amount
; we're moving frames down by
mov di,cx ;go on to next frame
jmp short Update_Gosub_Ptrs
Move_Gosub_Frames: ;now step (2), move frames down
mov cx,bp
sub cx,si ;cx points just past the end (himem)
; of range to be moved down
xchg ax,dx ;ax = amt to move gosub frames down by
mov si,[pGosubLast] ;start of range to move
mov di,si
sub di,ax
mov [pGosubLast],di
sub cx,si ;cx = number of bytes to move down
pop dx ;must pop this BEFORE we alter sp
sub sp,ax ;so interrupts won't overwrite gosub
; frames
rep movsb
mov di,dx ;di = old cbFrameVars
Check_FrameVar_Size:
.errnz MRS_cbFrameVars - PRS_cbFrameVars
mov dx,di ;dx = old cbFrameVars
mov cx,[bx.MRS_cbFrameVars]
sub cx,dx ;if cx > 0 then new vars have been added
DbAssertFlags ae,CODE,<excontxt: cbFrameVars got smaller!>
jbe Vars_Okay ;brif none have been added
;cx = number of bytes worth of new frame vars added to current frame
mov al,0
mov di,bp
sub di,[bx.MRS_cbFrameVars] ;di points to start of new frame vars,
cmp sp,di
jb Got_SP ;brif sp was moved down when gosub
; frames were
mov sp,di ;so interrupts won't overwrite this
; after the stosb
Got_SP:
rep stosb ;initialize new frame vars
Vars_Okay:
;fall into StartGrsContext
public StartGrsContext
StartGrsContext:
call DisStaticStructs ;ensure static structs deactivated
call SetSP ;set SP based on BP
ja StartGrs_Cont ;brif SP is in valid stack range
mov [b$ErrInfo],OMErr_STK ;out of stack space error
jmp OM_Err
StartGrs_Cont:
mov sp,ax
mov si,[grs.GRS_otxCur] ;Load the continuation address
xor ax,ax
mov [grs.GRS_flagsDir],al ;reset flags which get reset every
; time we begin executing pcode,
; or when a runtime error occurs.
public Start
Start:
call GetEsDi
Disp2:
mov [b$curframe],bp ;in case b$curframe got changed by
; the U.I. and not restored
DbChk BpChain ;ensure the bp chain is walkable
DispMac ; and begin execution
;***
;exStRunMain - Start program execution of the main module text
;Purpose:
; Perform the RUN statement (no arguments) - begin program execution.
;
;Input:
;Output:
;Modifies:
;***************************************************************************
MakeExe exStRunMain,opStRunMain
xor di,di ;Set context to beginning of text tabl
; (put this in di in case of runtime
; error)
mov ax,[grs.GRS_oMrsMain]
DbAssertRel ax,ne,UNDEFINED,CODE,<exStRunMain: grs.oMrsMain UNDEFINED>
Run_Otx:
cCall RsActivateCODE ;activate the main module
cmp [grs.GRS_fDirect],FALSE
jz RunMain1 ;brif from pcode - - - must reinit stack
or [b$CtrlFlags],NoSTACKINIT
;speed optimization for the case where
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -