📄 ssfor.asm
字号:
page 49,132
TITLE ssfor - scan support for For/Next
;***
;ssfor.asm
;
; Copyright <C> 1986, Microsoft Corporation
;
;Purpose:
; Scan For/Next.
;
; For executors utilize a For block that is allocated by the scanner.
; The allocation is from the frame.
;
; For opcode variants are:
; (IdLd,exp,exp[,exp]) opStFor<Step|> (UNDEFINED,UNDEFINED)
;
; For executor variants are:
; (IdRf,exp,exp[,exp]) exStFor<Step|><I2|I4|R4|R8|CY> (oFrame,oTxNext)
;
; where:
;
; oFrame is the offset to the For block, which contains step and limit
; oTxNext is the oTx of the oTx operand of the Next associated with
; this For. The For executor uses this oTx to branch to the
; Next executor to do the limit test for the first iteration.
;
; Next opcode variants are:
; ([IdLd|]) opStNext<Id|> (UNDEFINED,UNDEFINED)
;
; where:
; <Id|> indicates whether the user labeled the Next.
;
; The statement:
; Next i,j,k
; maps to several opStNextId opcodes.
;
; The Next executor variants are:
; (IdRf) exStNext<Id|><Step|><I2|I4|R4|R8|CY>
;
; The IdLd's of both For and Next are converted to IdRf.
; The scanner supplies the IdRf in the case that the Next is a
; opStNext. However, this Id is not listed and is removed at descan.
;
; Not all executor variants are unique. For example, the R8 variant
; of For supplies a Step of 1 if the user does not so specify. There
; need be no Step versions of R8 Next.
;
;Exceptions:
; Errors detected during For/Next scanning are:
; - Nesting errors (For without Next and Next without For).
; - Variable type errors (SD or user data types, arrays, or
; array elements
;
;For to Next binding:
; +------------------------+
; | V
; exStFor (oFrame,oTx) ... exStNext (oFrame,oTx)
; ^ |
; +----------------------+
;
;
;****************************************************************************
.xlist
include version.inc
IncludeOnce context
IncludeOnce qbimsgs
IncludeOnce scanner
IncludeOnce ssint
IncludeOnce txtmgr
IncludeOnce variable
.list
assumes ds, DATA
assumes es, NOTHING
assumes ss, DATA
assumes cs, SCAN
sBegin SCAN
subttl For
page
;***
;Ss_For - Scan For statement
;Purpose:
;
; Scan For statement. The following tasks are performed:
; 1. Make a For scan stack entry - each item is a word:
; For identifier flags
; STYP_For
; STYP_Step
; oTx of For statement
; oTx for start of EXIT For chain (initially UNDEFINED)
; oTx of exIdRf opcode
; oTyp of For index
;
; 2. Convert IdLd to IdRf. Coerce step, limit, and initial value
; to the type of the index variable.
;
; 3. Map and emit the executor
; Executor calculation involves these factors:
; 1. opcode to exe map For this opcode
; From mpOpExe
; 2. Direct mode or main level code
; From grsCur
; 3. Data type of index variable
; From Ld stack entry
; 4. Whether Step is present.
; From RULE table index
;
;***************************************************************************
.erre low STYP_Step ;The following code and PEROPCOD.TXT assume that the
;STYP_Step bit is one of the bits in the low byte.
;This flag is obtained from mpOpRule where it is set
;as <low STYP_Step> and the mpOpRule byte is loaded into
;the low byte below.
SsProc For,Rude
;Calculate STYP_Step for this For
push bp ; Set up local frame pointer to ease
mov bp,sp ; access to index variable oTyp
shr bx,1
test mpOpRule[bx],STYP_Step ; Step clause present?
jz NoStep ; Brif no step clause
mov ax,[bp+14] ; Get oTyp of index (Record = ET_RC)
mov cx,3 ; Coerce three values
jmp short CoerceFor
NoStep:
mov ax,[bp+10] ; Get oTyp of index (Record = ET_RC)
mov cx,2 ; Coerce two values
CoerceFor:
pop bp ; Restore BP. Discard frame pointer.
.erre ST_Typ_Mask EQ 0ffh ; Assure CBW is sufficient
.erre ET_MAX LT 80h ; Assure CBW is sufficient
cbw ; Clear flags in scan stack
call SsCoerceN
xor ch,ch
mov cl,mpOpRule[bx] ;cx now has correct value for STYP_Step
shl bx,1 ;Back to opcode * 2
mov dx,bx ; Save in dx
;Obtain the IdLd executor address, check type of For index.
pop ax ; oTyp of For index (Record=ET_RC)
pop bx ; oTx of For index
push ax
call MakeRef ;Convert IdLd to IdRf
pop ax ;Get type back
and ax,ST_Typ_Mask ; Map to ET_type
.erre ET_RC EQ 0 ; Assure JZ is sufficient
jz ForTypeBad ; For index is a record
.erre ST_Typ_Mask EQ 0ffh ; Assure we can use AL
cmp al,ET_MaxNum ; Numeric type?
jbe ForTypeOK
ForTypeBad:
mov al,ET_I2 ; Leave a valid type
ForTypeOK:
push ax ;FRAME gets type
push bx ; FRAME gets IdRf executor oTx
;Begin mapping to executor
dec ax
shl ax,1 ;AX = zero relative word offset
mov bx,dx ; opcode*2 back to bx
mov bx,mpOpExe[bx] ;Address of executor map
add bx,ax ;Address of executor for this For
mov ax,word ptr cs:[bx] ;Load ...
STOSWTX ;... and emit the executor
MOVSWTX ;Copy current For block offset
.errnz UNDEFINED - 0FFFFH
mov dx,UNDEFINED ;Get an UNDEFINED to push as the
; EXIT For link head
push dx ;FRAME gets initial EXIT For link
push di ;FRAME gets address of oTx for this For
or cx,STYP_For ;cx = scan frame identifier
push cx ;FRAME gets frame identifier
MOVSWTX ;Skip over oTx operand
jmp [ScanRet] ; and back to the scan loop
subttl ForBlockAlloc - allocate the For block
page
;***
;ForBlockAlloc - allocate the For block
;Purpose:
; For/Next executors require a For block to store limit and Step.
; This block is allocated when scanning For.
;
; The block is allocated from the current frame (the same as
; frame space for dynamic variables).
;
; A For may be scanned several times during the course of user program
; development. For blocks may be active during user edition. For
; block allocation supports CONT by utilizing the currently allocated
; block for the For if one exists.
;
;Input:
; cx = STYP_Step
; dx = data type of For
;
;Output:
; ax = new For block offset
;Preserves:
; bx,cx,dx
;***************************************************************************
ForBlockAlloc:
;Calculate bytes required for this For block
mov ax,dx
call CbTypOTypSCAN ; bytes for data type
cmp dx,ET_I2 ;Only I2 can have no Step
jnz ForStepCom ; as For supplies Step for other types
test cl,STYP_Step ;Is Step present?
jz ForNoStepCom ;No Step, so ax = For block size
ForStepCom:
shl ax,1 ;Times 2 for Step
ForNoStepCom:
;ax = bytes for For block
test byte ptr [grs.GRS_oRsCur+1],80H ;Module or procedure level?
jnz ProcLevel
add ax,mrsCur.MRS_cbFrameVars ;Get current top of frame
mov mrsCur.MRS_cbFrameVars,ax ;Put back new top of frame
jmp short MakeOBP
ProcLevel:
;Allocate the For block from the frame of the current procedure.
add ax,prsCur.PRS_cbFrameVars ;Get current top of frame
mov prsCur.PRS_cbFrameVars,ax ;Put back new top of frame
MakeOBP:
neg ax ;oBP
ret
subttl For Opcode to Executor maps
page
public mStForOpExe
mStForOpExe:
DWEXT exStForI2
DWEXT exStForI4
DWEXT exStForR4
DWEXT exStForR8
public mStForStepOpExe
mStForStepOpExe:
DWEXT exStForStepI2
DWEXT exStForStepI4
DWEXT exStForStepR4
DWEXT exStForStepR8
subttl Next
page
;***
;Ss_Next, Ss_NextId
;Purpose:
; Scan For/Next.
;
; Next opcode variants are:
; ([IdLd|]) opStNext<Id|> (UNDEFINED,UNDEFINED)
;
; where:
; <Id|> indicates whether the user labeled the Next.
;
; The statement:
; Next i,j,k
; maps to several opStNextId opcodes.
;
; The Next executor variants are:
; (IdRf) exStNext<Id|><Step|><I2|I4|R4|R8|CY>
;
; The scanner supplies the IdRf in the case that the Next is a
; opStNext. However, this Id is not listed and is removed at descan.
; Bit 0 of the oBP field is set if the IdRf was not inserted (due
; to out-of-memory or a previous error).
;
; Not all executor variants are unique. For example, the R8 variant
; of For supplies a Step of 1 if the user does not so specify. There
; need be only a Step versions of R8 Next.
;
; For blocks are allocated at Next scan time. If the For already
; has a valid oBP (i.e., not -1), then it is used. Otherwise,
; if the Next has a valid oBP, it is used. If neither are valid,
; then a new oBP is allocated and CantCont is set. This method allows
; either a For or Next (but not both) to be edited and still retain
; their previous For block.
;
; However, a previous For block can only be used if its type and size
; have not changed. This can only happen when the For is edited, not
; the Next. In order to tell, the oText field of the Next is set at
; descan time to have the oTyp and the Step flag. (Step only matters for
; I2, where a step of 1 uses a separate executor instead of a word in
; the For block.)
;
;For to Next binding:
; +------------------------+
; | V
; exStFor (oFrame,oTx) ... exStNext (oFrame,oTx)
; ^ |
; +----------------------+
;
;Scan time tasks include:
; 1. Detect nesting error (Next w/o For)
; 2. Change IdLd to IdRf, or insert IdRf if not an Id variant of Next.
; 3. Calculate and emit the executor
; Factors include:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -