📄 ssrules.asm
字号:
page 49,132
TITLE ssrules - Scanner Table Definitions
;***
;ssrules.asm - Scanner Table Definitions
;
; Copyright <C> 1986, Microsoft Corporation
;
;Purpose:
;
; This module defines the coercion and rules tables used by the scanner.
; The following is a description of how all scan tables are organized.
;
; tOpSsDisp: tOpAtr: tOpRule: tOpExe:
; ssOp1 op1Atr op1Rule ex1
; ssOp2 op2Atr op2Rule ex2
; ... ... ... ...
;
; tOpSsDisp is the scan dispatch for the opcode. Entries are 1 word.
;
; tOpAtr is the atribute byte for the opcode. Entries are 1 byte. The
; atribute value is the number of operand bytes owned by the opcode.
; Some opcodes own a variable number of operand bytes. In these cases
; the first operand word is the number of operand bytes - 2. This is
; signified by LOW UNDEFINED in the atribute table.
;
; tOpRule is a scan helper byte that can be:
; 1. a rule table index. Used in this way when there are more than one
; variables in the opcode to executor algorithm. The rule table index
; is used to index tRuleWord and tRuleByte desribed below.
; 2. an ET type. Used in this manner when the emitted type is the only
; variable in the opcode to executor algorithm. An example is all
; intrinsic functions that have no operands (ERR, ERL,...).
;
; tOpExe is the executor for the opcode. If an opcode has several executors
; then tOpExe contains the address of an ordered list of executors for
; the opcode.
;
; tRuleWord:
; This table usually contains one of the following:
; 1. coercion table address
; 2. other scan routine specific information such as an ET type.
;
; tRuleByte:
; This table almost always contains an ET type which is the emitted
; type for opcodes using this rule. The special emitted type
; LOW UNDEFINED indicates that the coerced input type is to be emitted.
; For example, opAdd emits an I2 when the arguments are I2.
;
; tCo<rule>
; These are the coercion tables. They are either one or two dimensional
; and overlay each other as much as possible in order to save space.
; Coercion tables contain:
; 1. ET types. These are present when coercion may be required. The
; type is the target type to which the current argument(s) must be
; coerced.
; 2. 0. This value is used as a speed hack. It is present when it is
; known that coercion is not required.
; 3. LOW UNDEFINED. This value is used to indicate "type mismatch"
; was detected.
;
; tCoerceExe is a 2 dimensional (typeXtype) table of coercion executor
; addresses.
;
;In general, these tables are accessed as follows (refer to following diagram):
; 1. The opcode is used to index into tOpRule to find the rule index
; for the current op. This allows a single scan routine to scan
; a family of related opcodes.
; 2. The rule index is used to find the coercion table and the emitted
; type for the current op.
; 3. Arguments are popped from the scan stack and used to index the
; coercion table.
; 4. For opcodes that emit a value the emitted type and current
; expression fragment pcode address are pushed on the stack.
;
; tOpRule: tRuleWord: tRuleByte:
; [index]
; opcode-------->[index]--------> [ptCoerce][ET_emit]
; [... ] |
; +---------------->tCoerce
;
;
;****************************************************************************
.xlist
include version.inc
SSRULES_ASM = ON
IncludeOnce context
IncludeOnce opintrsc
IncludeOnce pcode
IncludeOnce qbimsgs
IncludeOnce ssint
IncludeOnce txtmgr
IncludeOnce variable
.list
assumes cs, SCAN
assumes ds, DATA
assumes SS, DATA
sBegin CODE
extrn exLitI21:near ;Literal executor
extrn exPushSeg:near
extrn exCopyTmpAr:near
sEnd CODE
subttl Coercion Label Definitions
sBegin SCAN
extrn GetTrueType:near
mOpExLitR8 label word
DWEXT exLitR80
DWEXT exLitR81
DWEXT exLitR82
DWEXT exLitR83
DWEXT exLitR84
DWEXT exLitR85
DWEXT exLitR86
DWEXT exLitR87
DWEXT exLitR88
DWEXT exLitR89
DWEXT exLitR810
subttl Coercion Support Functions
page
;***
;SsCoerceN - coerce n expressions on the scan stack to specified type
;Purpose:
; Coerce n expressions on the scan stack to specified type.
;
;Input:
; ax = oTyp of target (Record = ET_RC)
; cx = count to coerce
; si/di scan source and destination in pcode
;Output:
; si/di updated if any coercion was required.
; f_StaticCalc set FALSE if any expression was not a literal
;
;Preserves:
; ax,bx
;***************************************************************************
public SsCoerceN
SsCoerceN:
pop [SsParmCnt] ; Get return address out of the way
jcxz EndCoerceN
.erre ET_RC EQ 0 ; Assure DEC is sufficient
dec ax ; Force ET_RC -> 0ffffh
cmp ax,ET_MaxNum ; Numeric type?
jb SsCoerceNStart
call TMError
xor ax,ax ; Use valid type (ET_I2)
SsCoerceNStart:
inc ax ; Restore correct oTyp
SsCoerceNLoop:
pop dx ; Get oType
push dx ; But keep it on stack
xor dh,high ST_Lit? ;High bits now zero if literal
test dh,0C0H ;Determine if this index is a literal.
jz SsCoerceNNotLit ;Not a literal index
mov f_StaticCalc,FALSE ;Indicate not a $STATIC array if this
SsCoerceNNotLit: ; is the first reference.
test dh,ST_ByVal+ST_Seg ; Have ByVal or Seg been used?
jz @F ; Brif no
call TMError
@@:
call EnsureArgType
loop SsCoerceNLoop ;Go check next index
EndCoerceN:
jmp [SsParmCnt] ; Return to caller
page
;***
;EnsureArgType
;Purpose:
; Ensure that the expression entry on the stack is of the desired
; type.
;Input:
; ax = type required for this expression
; si/di scan source and emit
;
; ParmW oTxExp
; ParmW oTypExp (Records use ET_RC)
;
;Output:
; ax = oTyp of target (Records use true oTyp)
;Preserves:
; bx,cx,dx
;****
cProc EnsureArgType,<NEAR,PUBLIC>,<ax,bx,cx,dx>
ParmW oTxExp
ParmW oTypExp
cBegin
mov bx,oTxExp ;Expression location
cmp ax,ET_MaxNum ; Is target numeric ?
xchg cx,ax ;CX = oTyp of target
jbe Numeric
mov ax,oTypExp ;AX = oTyp of source (Record = ET_RC)
TestX ax,ST_Var? ;Is it a variable?
jz Coerce ;If not, it won't move
mov dh,0 ;Assume near - SD/FS
or al,al ;[5] Is it a record?
jnz SafeRef ; Make sure reference is safe
mov dh,FarArg ;Must be record - want far ref
SafeRef:
call SsRefArg ;Make sure it's safe from moving
Numeric:
mov ax,oTypExp ;AX = oTyp of source (Record = ET_RC)
Coerce:
call SsCoerceReg
cEnd
;SsCoerceReg
;
;Purpose:
; Insert a coercion token to cause an expression to be coerced to a
; specified type.
;
; Literals 0 through 10 may be coerced from I2 to R4 by modification
; of the executor for these literals.
;
; If types match, no action is performed.
;
;Inputs:
; ax = oTyp of expression (with high bits set) (Record = ET_RC)
; bx = oTx of expression
; cx = oTyp of target
;Outputs:
; bx = oTx of expression, after coercion
; si and di updated if insertion needed
;Exceptions:
; If expression or target type is not numeric, Type Mismatch Error
; is generated.
;
; Coercion token insertion may cause the text table to grow. This
; may result in OME.
public SsCoerceReg
SsCoerceReg:
cmp ax,ET_I2+ST_Lit ;Determine if lit without operand
jne NoLitCoerce ;Can't optimize by replacing lit executor
cmp cx,ET_R4
jz LitCoerce
cmp cx,ET_R8
jne NoLitCoerce
LitCoerce:
;Target type is R4/R8, so replace executor with 1 word 8087 literal
mov dx,bx ;Preserve address of this executor
mov bx,PTRTX[bx-2] ;Load literal executor
GetCodeIntoDs SCAN
mov bl,byte ptr [bx-1] ; Load MSB of opcode
push ss
pop ds
.erre OPCODE_MASK EQ 03ffh ; Assure following code is ok
; and bx,HIGH (NOT OPCODE_MASK)
and bx,0fch ; Clear unwanted bits
shr bx,1 ; Convert to word offset
mov ax,mOpExLitR8[bx] ; Get corresponding R8 lit executor
mov bx,dx ;Restore address of I2 executor in text
mov PTRTX[bx-2],ax ;Store the new R4 literal executor.
EndCoerce:
ret
RecordChk:
; At this point, the coercion has been determined to be from a record.
; However, the true oTyp of the record is not saved on the scan stack
; ET_RC was used instead. This code will use the oTx of the IdLd to
; find the oVar and in turn the true oTyp of the source. This is
; then compared to CX to check that types match. No coercion is
; possible among records so there is either an error or nothing.
;
; ax = oTyp of source expression
; bx = oTx of source expression
; cx = oTyp of target
;In non-SizeD versions, it is possible that the oTx from the scan
;stack will point after an exCopyTmpAr and exPushSeg instead of an
;exIdLd, exAIdLd, or exOffLd. To differentiate between the two, the
;exPushSeg executor is forced to start at an odd address. Since an
;oVar and oElem must be even, the exPushSeg can be recognized.
cmp PTRTX[bx-2],codeOFFSET exPushSeg
jne @F ; Brif exIdLd, exAIdLd, or exOffLd
DbAssertRel PTRTX[bx-10],e,<codeOFFSET exCopyTmpAr>,SCAN,<SsCoerceReg: exCopyTmpAr>
sub bx,10 ; Backup over inserted executors
@@:
mov dx,cx ; DX = oTyp of target
call GetTrueType ; CX = oTyp of source
cmp cx,dx ; Do oTyps match?
public TMError,TMErrorNZ
TMErrorNZ:
;Report type mismatch error if Z flag not set.
jz NoError
TMError:
;Report type mismatch error. All registers preserved.
push ax
mov ax,ER_TM ;Type mismatch error
call SsError
pop ax
NoError:
ret
NoLitCoerce:
;Calculate the implicit coercion executor by entering tImpCo as a two
;dimensioned table of executor addresses.
.erre ET_RC EQ 0 ; Assure JZ is sufficient
or al,al
jz RecordChk ; Brif source is record
cmp cx,ET_MAX ; Is target a primitive type?
ja TMError ; Brif not. This is an error
call MSdFs ; Map ET types: FS=SD
xchg ax,cx ; AX = Target type
call MSdFs ; Map target type too
cmp ax,cx ;Types already match?
je EndCoerce ; If match, skip coercion
.erre ET_SD EQ 5
add ax,cx ;AX = Source + Target
shl cx,1 ;CX = Source * 2
shl cx,1 ;CX = Source * 4
add ax,cx ;AX = Source * (5|7) + Target
xchg ax,bx ;AX = oTx, BX = Table index
shl bx,1 ;To word index
mov cx,tImpCo[bx] ;Enter coercion executor table for executor
xchg bx,ax ; oTx to bx
jcxz EndCoerce
mov ax,cx ;Executor to insert to ax
dec cx ; Is this 1 (incompatible types)?
jcxz TMError ; Brif yes
; jmp short Insert ;Fall into Insert, below
;*** Insert - Insert word into pcode
;
;Inputs:
; ax = word to insert
; bx = oTx to insert
; cx = Number of bytes to make room for (InsertCx only)
; si = scan source
; di = scan destination
;Outputs:
; cx = number of bytes inserted
; bx = input bx + output cx: oTx of point after insertion
; si, di updated for text moves
;Exceptions:
; If OME:
; Error recorded by SsError
; Carry flag set
;Preserves:
; ax,bx,dx (bx updated)
public Insert,InsertCx,InsertBranchBos,InsertBranch,Insert1Op
extrn exBranch:near
Insert:
mov cx,2 ;Make room for two bytes
InsertCx:
cmp [SsErr],0 ;Any errors?
jnz InsertFail ;Don't let error location get invalid
push ax
push bx
push cx
push dx
;Ensure room. This may cause source side of text to move within the segment.
call SsEnsureGap ;Ensure reasonable gap size
pop dx
pop cx
pop bx
pop ax
jc InsertOME ;Out of memory error
or [SsBosFlags],SSBOSF_Inserted ;Remember insertion occured
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -