📄 ssrude.asm
字号:
page 49,132
TITLE ssrude - Scan and Descan support routines for SS_RUDE mode
;***
;ssrude - Scan and descan support for SS_RUDE mode
;
; Copyright <C> 1986, Microsoft Corporation
;
;Purpose:
;
; Certain opcodes require work to scan from SS_RUDE to SS_PARSE and
; back. This module contains most of the dispatched entrypoints
; for performing this work.
;
; The connection between scan routines and descan routines is as
; follows:
; - Each scan routine is declared with macro SsVProc. If there is
; work required to get to/from SS_RUDE then the optional parameter
; "rude" is specified on the SsVProc invocation. Each scan dispatch
; so declared will have the address of the rude mode scan/descan
; routine stored in the scanner segment at the SsVProc entrypoint -
; SsVProcRude.
; - The scan and descan main loop will vector through the above address
; when the mpOpAtr entry for the opcode indicates that work is required
; to get to or from SS_RUDE mode.
; - The dispatched routine will determine whether the current operation
; is scan or descan by branching on PSW.Z. PSW.Z set indicates
; descan from SS_PARSE to SS_RUDE. PSW.Z clear indicates scan from
; SS_RUDE to SS_PARSE.
;
; Rude scan/descan dispatches are entered with the following convention:
; ax = oTyp from rule table (for opId's only)
; cx = opcode
; dx = pVariable table (Descan to SS_RUDE only)
; si = descan source
; di = descan destination
; es = text segment
; PSW.Z set indicates SS_PARSE -> SS_RUDE
;
; Special Cases:
; -------------
; CONSTants
; When an opStConst statement is seen, we continue scanning
; IdLd pcodes normally, except that we give an error if
; MakeVariable finds one of these that is not already created
; as a CONSTant. Each time we find an IdSt pcode, we call
; ScanAndExec with the pcode expression we've just scanned
; ScanAndExec calls MakeVariable to create the new CONSTant
; variable, scans the expression to SS_EXECUTE, executes it
; (thus storing the value of the expression in the CONSTant),
; and then descans the expression back to SS_PARSE.
;
;
;*****************************************************************************
.xlist
include version.inc
SSRUDE_ASM = ON
IncludeOnce architec
IncludeOnce context
IncludeOnce names
IncludeOnce opcodes
; IncludeOnce opid
; IncludeOnce opmin
IncludeOnce optables
IncludeOnce parser
IncludeOnce pcode
IncludeOnce qbimsgs
IncludeOnce scanner
IncludeOnce ssint
IncludeOnce txtmgr
IncludeOnce ui
IncludeOnce variable
.list
;Invoked after calling any function which could cause heap movement
; and thus, movement of the current text table being scanned.
; This macro preserves all registers except ES (including flags)
;
SsRefreshES MACRO
GETSEGTXTCUR ; ES = current pcode segment,
; all other registers preserved,
; including flags
ENDM
assumes ds, DATA
assumes es, NOTHING
assumes SS, DATA
sBegin DATA
globalW oNamOfPrsCur,UNDEFINED ;Speed optimization for rude scan
; set up here, used by varmgr
staticW otxConstCur,0 ;otx to start of current CONST expr
; if scanning a CONST stmt, else 0
staticW varFlags_Reset,0 ;Normally 0, set to FVI_SHARED,
; FVI_STATIC, FVI_COMMON, FVI_AUTO,
; or FVI_PUBLIC whenever one of those
; bits must be temporarily reset
; in mkVar.flags by IdLd.
; Always reset by HandleId.
staticB fErrWithinOp,0 ;set to 1 if an error occurred within
; the operand of a big opcode (like
; opStDeclare), so error can be
; reported at the operand.
staticW spErrorRestore,0 ;used for error recovery
sEnd DATA
sBegin SCAN
assumes cs,SCAN
page
;***
;SsRudeScan
;Purpose:
; Move text between SS_PARSE and SS_RUDE.
;
; This routine dispatches to the same entrypoint for moving
; text in either direction. The individual entrypoints must
; examine PSW to determine which direction to take the current
; opcode.
;
; Rude mode register convention is:
; ax = opcode
; dx = mrsCur.MRS_bdVar_pb (if not SizeD)
; es:si/di = source and destination pointers
; PSW.Z set indicates descan from SS_PARSE to SS_RUDE
; reset indicates scan from SS_RUDE to SS_PARSE
;
; Dispatching is performed for all opcodes. Table space is
; conserved by placing the rude dispatch as a prefix to the non-rude
; scan dispatch entrypoint for the opcode. Note that this restriction
; limits the resolution of the rude scan dispatching to that of the
; standard scan dispatching. In other words, there are no two opcodes
; with individual rude dispatches that have a common standard scan
; dispatch.
;
; A further space savings is that not all standard scan dispatches
; have rude dispatch prefixes. The scan entrypoint declaration macro
; SsProc has a second parameter that determines whether the rude
; dispatch is required. The opcode atribute table mpOpAtr contains
; a bit (OPA_fSsRude) that indicates to the rude scan loop whether
; there is work to go to/from SS_RUDE for that opcode. All opcodes
; that do not have this bit set are dispatched to a common entrypoint
; that skips operands to the next opcode.
;
; The rude scans are wholly space invarient. The rude scan is
; a scan in place - it is not necessary for dispatch points to emit
; text that is not modified (for instance, it is not necessary to
; emit the opcode).
;
; Descanning from SS_PARSE to SS_RUDE can cause no errors.
;
; Scanning from SS_RUDE to SS_PARSE can cause errors. When a dispatch
; point finds an error it must:
; - record the variable in a static variable.
; - recover the opcode that it is processing to a consistent (RUDE or
; PARSE mode state (all operands must be in the same state).
; - replace the first SS_RUDE mode opcode in the text table with an
; opEot.
; - restart SsRudeScan to descan the pcode up to the opEot.
; - replace the opEot with the saved opcode.
; - return, reporting the error.
;
;NOTE: This is not a recursive scheme; an alternate reentry point is
; used to descan the pcode, and the opEot detects whether an error
; has occurred or not. Aside from the above mechanism, this routine
; is NOT reentrant.
;
; Error control variables are:
; SsErrOTx - text offset of pcode which was replaced by opEot
; descanner expects this to be UNDEFINED if no
; error has occured.
; SsErr - error code to be returned by scanner.
; SsErrOpcode - opcode which was replaced by opEot
;
;Entry:
; parmW target scan state (must be SS_RUDE or SS_PARSE)
;Exit:
; ax == 0 ----> Output registers are the same as for GetTXDInfo
; ax != 0 ----> ax = error code
; [grs.GRS_otxCur] = text offset to error. If low
; bit is set, error is within an operand (like opStSub,
; opStDeclare, etc.), so caller can position cursor
; exactly to the error token.
;
;************************************************************
cProc SsRudeScan,<PUBLIC,FNEAR>,<si,di>
parmB TargetState
cBegin
mov [spErrorRestore],sp ;in case an error occurs with
; stack in an intermediate state
sub ax,ax
mov [fErrWithinOp],al
dec ax ;ax = UNDEFINED
mov [SsErrOTx],ax ;initialize in case we're descanning
cmp [TargetState],SS_RUDE ;Indicate scan or descan
jz SsRudeDeScan ;brif descanning to SS_RUDE
call OtxDefType0Far ; set all 26 letter default
; types to initial default
SkipDT:
cmp [grs.GRS_fDirect],FALSE
jz Not_Direct ;brif not scanning direct mode buffer
push [grs.GRS_otxCONT] ; In direct mode,
call OtxDefTypeCurFar ; set all 26 letter defaults to
; values at the current program counter.
; If cant CONT (i.e. UNDEFINED), set
; them to their value at EOT
Not_Direct:
DbAssertRelB [TargetState],z,SS_PARSE,SCAN,<ssrude: invalid target state>
cmp [grs.GRS_oPrsCur],UNDEFINED
jz SsRudeScanErr ;brif not scanning a procedure table
cmp [grs.GRS_fDirect],FALSE
jnz SsRudeScanErr ;ignore prsCur stuff if in Direct Mode
push [prsCur.PRS_ogNam]
call ONamOfOgNamFar ;must succeed (as prs already exists)
DbAssertRel ax,nz,0,SCAN,<SsRudeScan: [6] ONamOfOgNam returned an error>
mov [oNamOfPrsCur],ax ;speed optimization - used by varmgr
call MakePrsTVar ;make var hash table for prsCur
or ax,ax ;error return?
jnz SsRudeScanErr ; brif not
PUSHI ax,ER_OM ;insufficient memory - - exit
jmp ErrExit
SsRudeDeScan: ;only get here if we're descanning
DbAssertRelB [grs.GRS_fDirect],z,FALSE,SCAN,<ssrudedescan: fDirect TRUE>
;don't want to reset otxCONT when dealing with the Direct Mode buffer,
; so we're counting on the fact that we never descan the D.M. buffer
mov [grs.GRS_otxCONT],UNDEFINED
;ensure this is correctly set whenever
; we descan any text table
SsRudeScanErr: ;reentry point in case of scan error
SsRefreshES ;es = cur pcode seg (heap movement)
mov dx,[mrsCur.MRS_bdVar.BD_pb] ;Address of variable table
SetStartOtx si ;Start scan from the top
mov di,si ;Destination = source
RudeLoop:
LODSWTX ;Pick up opcode
mov bx,ax
and bx,OPCODE_MASK ; ax is actual opcode, bx is
; masked opcode
DbAssertRel bx,be,op_max,SCAN,<Rude Scan Loop: opcode out of range.>
DbAssertRel spErrorRestore,e,sp,SCAN,<Rude Scan Loop: Stack Use Err.>
DbAssertRel si,ae,di,SCAN,<Rude Scan Loop: Emit overran source.>
DbAssertRel es,z,EScheckRude,SCAN,<Rude Scan Loop: ES not preserved>
mov cl,mpOpAtr.[bx] ;load attribute byte
test cl,OPA_fSsRude ;Test for scan work for rude mode
jnz RudeScanWork ;Work required to get to SS_RUDE
Ssv_NOps: ;Skip opcode and operands
and cx,OPA_CntMask ;get the operand count from attribute
.errnz OPA_CntMask AND 0FF00H ;must use cx in next line if non-zero
cmp cl,OPA_CntMask ;check for cnt field in operand
jz Fetch_Cnt ; brif there is a cnt field
Bump_TxtPtr:
add si,cx
jmp RudeLoop ;start over for next operand
Fetch_Cnt:
LODSWTX ;load the cnt field
mov cx,ax
inc cx
and cl,0FEH ;round up to even byte count
jmp short Bump_TxtPtr
RudeScanWork:
mov di,si ;Bring destination in line with source
mov al,ah ; al contains oTyp for opId's,
; but left shifted
SHIFT H,R,al,2 ; shift al right two bits
.errnz OPCODE_MASK - 03FFH ; 03FF mask implies it's shifted
; left two bits.
cbw ;ax = oTyp for opId's
mov cx,bx ; cx = masked opcode
shl bx,1 ;To word offset
mov bx,[bx].mpOpScanDisp ;Scan dispatch address
DbPub DispSSR ;a handy public for debugging
cmp [TargetState],SS_RUDE ;Indicate scan or descan
DispSSR:
jmp word ptr cs:[bx].SsProcRude ;Dispatch to RUDE scanner
;***
;SsVProc Eot
;Purpose:
; Rude scan/descan dispatch.
;
;Input:
; Standard rude dispatch
;Output:
;************************************************************
SsVProc Eot
jnz SsRudeOkX ;if scanning and got to opEot, no errors
mov ax,UNDEFINED
cmp [grs.GRS_fDirect],FALSE
jnz Eot_Cont1
mov bx,dataOFFSET mrsCur
cmp [grs.GRS_oPrsCur],ax
jz Eot_Cont ;brif not scanning a procedure table
mov bx,dataOFFSET prsCur
mov [prsCur.PRS_oVarHash],ax
;must ensure this gets reset here, in
; case we were called to descan a
; prs with an empty text table
Eot_Cont:
.errnz PRS_cbFrameVars - MRS_cbFrameVars
mov [bx.PRS_cbFrameVars],-FR_FirstVar
; reset to init. value. This value
; is 2 to account for the fact that
; b$curframe is always pushed on the
; stack after bp, so we treat this
; word as a frame var for ref'ing
; the real frame vars off of bp
Eot_Cont1:
;reset to default
cmp [SsErrOTx],ax ;did we just descan due to a scan err?
jz SsRudeOkX ;No error - exit.
mov di,[SsErrOTx]
mov ax,[SsErrOpcode]
STOSWTX ;restore the saved opcode in text table
push [SsErr] ;in case ModuleRudeEdit changes this
ErrExit:
cmp [grs.GRS_fDirect],FALSE
jnz Eot_Err_Exit ;don't call ModuleRudeEdit if error
; in scanning Direct mode buffer - -
; no need to do so.
call ModuleRudeEditFar ;discard vartable, reset name table bits
mov [spErrorRestore],sp ;refresh (ModuleRudeEdit recursively
; calls SsRudeScan which changes this)
Eot_Err_Exit:
pop ax ;retval
SsRudeErr: ;ax = error code, set carry and return
jmp short SsRudeX
SsRudeOkX:
mov al,[TargetState]
cmp [grs.GRS_fDirect],FALSE
jnz SsRudeX1 ;brif just scanned direct mode buffer
mov [txdCur.TXD_scanState],al
;in case we had a DEF FN without an END DEF (an error the execute
; scanner will catch), deactivate prsCur if the current text table
; is for mrsCur
test [txdCur.TXD_flags],FTX_mrs
jz SsRudeX1 ;brif a prs is active
call PrsDeActivateFar ; in case we had a DEF FN w/o an END DEF
SsRudeX1:
DbMessTimer SCAN,<Leave SsRudeScan - >
sub ax,ax ; Indicate success
SsRudeX:
mov [oNamOfPrsCur],UNDEFINED ;reset to default value
cEnd
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -