📄 prscg.asm
字号:
cmp [pdcl.PDCL_cParms],ax
jne MarkDisp ;brif got a parm list
dec [pdcl.PDCL_cParms] ;set to UNDEFINED so scanner knows
; to not use this for parm
; type/count checking
jmp SHORT MarkDisp
NotDeclare:
;If we don't get MARK(4), this SUB/FUNCTION has no STATIC keyword
and [prsCur.PRS_flags],NOT FP_STATIC
;-------------------------------------------------
;walk through MARK(xxx) entries from left to right
;-------------------------------------------------
MarkDisp:
mov si,MAX_STK_MARK
DeclMarkLoop:
cmp [pCurStkMark],si
jne DeclNextMark
jmp SHORT DeclEndOfMarks
DeclNextMark:
dec si
dec si
mov di,[si] ;di = oDstOpcode
dec si
dec si
mov ax,[si] ;ax = al = markId
dec ax
DbAssertRel ax,be,9,CP,<Unexpected MARK in CgDeclare()>
shl ax,1
xchg ax,bx ;bx = 2 * (markId - 1)
jmp WORD PTR cs:DeclDispTbl[bx] ;dispatch based on markId
DeclDispTbl:
DW DeclMark1 ;CDECL
DW DeclMark2 ;ALIAS
DW DeclMark3 ;parms (before left paren)
DW DeclMark4 ;STATIC
DW DeclMark5 ;single line DEF
DW DeclMark6 ;1st parm (after left paren)
;MARK(1): Got CDECL directive
DeclMark1:
call ErrIfPrsHasTxtTbl
jne DeclMarkLoop ;brif prs has a text table
.errnz DCLA_cdecl - 8000h
or [procAtr_HI],80h ;remember we got CDECL
jmp SHORT DeclMarkLoop
;MARK(2): Got ALIAS directive
DeclMark2:
call ErrIfPrsHasTxtTbl
mov [oDstAlias],di ;save offset to opLitSD("<alias>")
jmp SHORT DeclMarkLoop
;MARK(3): got offset to formal parm list
DeclMark3:
mov [oDstParms],di
jmp SHORT DeclMarkLoop
;MARK(4): got STATIC keyword at end of proc definition
DeclMark4:
or [prsCur.PRS_flags],FP_STATIC
jmp SHORT DeclMarkLoop
;MARK(5): got single line DEF FN
DeclMark5:
mov [oDstEndDef],di
mov ax,opEndSingleDef
call Emit16_AX
mov ax,2
call Emit16_AX ;emit cntEos word
call Emit16_0 ;emit space for link field
jmp SHORT DeclMarkLoop
;MARK(6): got ( [parmlist] )
DeclMark6:
cmp [pdcl.PDCL_cParms],UNDEFINED ;so scanner knows to not use this
; for parm type/count checking
jne DeclMarkLoop ;brif got a parm list
inc [pdcl.PDCL_cParms] ;so scanner knows to use this declare
; for parm type/count checking
jmp SHORT DeclMarkLoop
DeclEndOfMarks:
;Copy Alias text after formal parms
mov ax,[oDstAlias]
or ax,ax
je NoAliasArg
call CopyLit ;ax = cbAlias
mov [cbLibInfo],ax
shl al,1
shl al,1
.errnz DCLA_cbAlias - 7C00h
or [procAtr_HI],al ;save cbAlias in pcode field
;squeeze source of ALIAS lit out of pcode buffer
;BdShiftLeft((bd *)&ps.bdpDst, oDstAlias, oDstParms - oDstAlias)
PUSHI ax,<dataOFFSET ps.PS_bdpDst>
push [oDstAlias]
mov ax,[oDstParms]
sub ax,[oDstAlias] ;ax = number of bytes to delete
push ax
sub [oDstParms],ax ;update for the left shift
sub [oDstEndDef],ax ;update for the left shift
call BdShiftLeft ;grow buf, can cause heap movement
NoAliasArg:
;Now make room for things to insert before parm list:
; opcode, byte-count-till-end-of-stmt, link field for DEF FNs, oPrs
mov si,10 ;assume we need to insert 10 bytes
cmp [pdcl.PDCL_procType],PT_DEFFN
jne NotDefFn1 ;brif not DEF FN stmt
inc si ;need 2 extra bytes for link field
inc si
NotDefFn1:
;BdShiftRight((bd *)&ps.bdpDst, oDstParms, cbInsert)
PUSHI ax,<dataOFFSET ps.PS_bdpDst>
push [oDstParms]
push si ;pass cbInsert parm
call BdShiftRight
or ax,ax
jne ShiftOk ;brif no out-of-memory error
call ParseErrOm ;Error "Out of memory"
jmp SHORT DeclExit
ShiftOk:
call SetDstPbCur ;update ps.bdpDst.pbCur after BdShift...
push ds
pop es ;es = ds for stosw below
mov di,[oDstParms]
add di,[ps.PS_bdpDst.BDP_pb]
mov ax,[opcode]
stosw ;store opcode in pcode buffer
;emit cntEos operand
mov ax,[oDstEndDef]
sub ax,[oDstParms]
add ax,si ;include cbInsert
add ax,[cbLibInfo] ;add #bytes in LIB and ALIAS clause
sub ax,4
inc ax ;round up to even byte count
and al,0FEH
stosw ;store cntEos operand
cmp [pdcl.PDCL_procType],PT_DEFFN
jne NotDefFn2 ;brif not DEF FN stmt
stosw ;leave room for DEF FN link field
NotDefFn2:
mov ax,[pdcl.PDCL_oPrs]
or ax,ax
jns NotUnboundDefFn
mov ax,[pdcl.PDCL_oNam] ;for [DECLARE] DEF FNs, in SS_RUDE
;state, emit the oNam
NotUnboundDefFn:
stosw ;store oPrs/oNam operand
mov ax,[procAtr]
stosw ;store proc's oTyp
mov ax,[pdcl.PDCL_cParms]
stosw ;store cParms operand
DeclExit:
cEnd
;*********************************************************************
; CopyLit(ax:oDstLit)
; Purpose:
; Move the ASCII text of an opLitSD to the end of the pcode buffer.
; If string is longer than 255 bytes, it is truncated.
; Entry:
; ax = offset into pcode buffer to opLitSD opcode
; [EB] bx = TRUE iff length of string is to output as byte preceeding
; text of string.
; Exit:
; string is moved to end of pcode buffer and the opLitSd is removed
; ax = length of string
;
;*********************************************************************
CopyLit PROC NEAR
push si
mov si,ax
add si,[ps.PS_bdpDst.BDP_pb]
lodsw ;skip opLitSD opcode
DbAssertRel ax,e,opLitSD,CP,<CopyLit: expected opLitSD>
lodsw ;ax = cb operand from opLitSD
or ah,ah
je LenOk
mov ax,255 ;truncate string
LenOk:
push ax ;save for return value
inc ax ;round up to word count
shr ax,1
mov cx,ax
jcxz CLitExit ;brif entire string has been copied
CLitLoop:
push cx ;save word count
lodsw ;ax = next 2 bytes of string
sub si,[ps.PS_bdpDst.BDP_pb] ;Emit16 can cause heap movement
call Emit16_AX
add si,[ps.PS_bdpDst.BDP_pb] ;reconvert offset to pointer
pop cx ;restore word count
loop CLitLoop
CLitExit:
pop ax ;ax = string length
pop si
ret
CopyLit ENDP
;*********************************************************************
; CgCall(opcode)
; Purpose:
; Called to generate pcode for the following bnf:
; tkCALL (MARK(1) IdImplicit
; [tkLParen IdCallArg {tkComma IdCallArg} tkRParen])
; tkCALLS MARK(1) IdImplicit
; [tkLParen IdCallArg {tkComma IdCallArg} tkRParen]
;
;*********************************************************************
PUBLIC CgCall
CgCall PROC NEAR
push si ;save caller's si
mov bx,MAX_STK_MARK
mov si,[bx-2] ;si=offset in pcode for item after MARK
push ax ;save opcode for Emit16 below
mov bx,[ps.PS_bdpDst.BDP_pb]
mov ax,[bx][si] ;ax = oNamIdSub
call SubRef ;ax = oPrs for sub being called
;We can ignore error results, because
;if error occurs, no code will ever
;try to activate this oPrs, because
;line will be stored as opReParse
;delete the information emitted by NtIdImplicit()
;BdShiftLeft((bd *)&ps.bdpDst, oDstCur, 2)
PUSHI dx,<dataOFFSET ps.PS_bdpDst>
push si
PUSHI dx,2
mov si,ax ;si = oPrs
call BdShiftLeft ;grow buf, can cause heap movement
call SetDstPbCur ;set ps.bdpDst.pbCur after BdShiftLeft
call Emit16 ;emit opcode pushed ~15 lines above
push [cIdArgs]
call Emit16 ;emit arg count
push si ;push oPrs
call Emit16
pop si ;restore caller's si
ret
CgCall ENDP
;*********************************************************************
; VOID NEAR CgRun(opcode)
; Purpose:
; Invoked to generate code for the following bnf:
; tkRUN [(Ln MARK(1)) | (Exp MARK(2))]; <CgRun()>
;
;*********************************************************************
PUBLIC CgRun
CgRun PROC NEAR
mov bx,[pCurStkMark]
cmp bx,MAX_STK_MARK
mov ax,opStRunMain ;ax = opcode to emit for RUN
je RunEmitExit ;brif simple RUN (no MARKs)
DbAssertRelB [bx],be,2,CP,<Invalid MARK id in CgRun()>
cmp BYTE PTR [bx],1
jne RunFile ;brif markId != 1 (RUN <filename>)
;Got RUN <line number>, insert opStRunLabel before Ln
mov bx,[bx+2] ;bx = pcode offset
dec bx
dec bx ;bx = pcode offset where opcode is to go
mov ax,opStRunLabel
call InsertOp ;insert word AX at offset BX
jmp SHORT RunExit
RunFile:
mov ax,opStRunFile
RunEmitExit:
call Emit16_AX
RunExit:
ret
CgRun ENDP
;*********************************************************************
; VOID NEAR CgInput(opcode)
; Purpose:
; Invoked to generate code for the following bnf:
;
; tkINPUT
; [(lbsInpExpComma MARK(16)) |
; (tkSColon MARK(2) [LitString MARK(4) (tkSColon | (tkComma MARK(1)))])|
; (LitString MARK(4) (tkSColon | (tkComma MARK(1))))]
; MARK(8) IdAryElemRef EMIT(opStInput) {tkComma IdAryElemRef
; EMIT(opStInput)}
; EMIT(opInputEos)
; <CgInput(opInputPrompt)>
;
; tkLINE tkINPUT
; [(lbsInpExpComma MARK(16)) |
; (tkSColon MARK(2) [LitString MARK(4) (tkSColon | (tkComma MARK(1)))]) |
; (LitString MARK(4) (tkSColon | (tkComma MARK(1))))]
; IdAryElemRef
; <CgInput(opStLineInput)>
;
; It maps syntax to pcode as follows:
; INPUT [;] [prompt (,|;) <list> =>
; [sdExp] opInputPrompt(cnt,mask,<typelist>)
; If prompt is followed by a semicolon, FINP_QSupress is not ORed into
; 'mask' which causes a question mark to be appended to the prompt
; string.
; The optional semicolon after INPUT causes FINP_CrLf not to be ORed into
; 'mask' which causes the user's terminating carriage return not to be
; echoed.
;
;*********************************************************************
PUBLIC CgInput
CgInput PROC NEAR
.errnz FINP_QSupress - 1
.errnz FINP_CrLf - 2
.errnz FINP_Prompt - 4
push si ;save caller's si
push di ;save caller's di
sub di,di ;init bit mask
mov bx,MAX_STK_MARK
;OR bit mask with to 1 for comma after prompt (MARK(1)),
; 2 for semicolon after INPUT (MARK(2)),
; 4 for prompt (MARK(4))
InpMarkLoop:
cmp [pCurStkMark],bx
je InpMarkLoopDone
dec bx
dec bx
mov si,[bx] ;si = oDstOpcode from mark stack
dec bx
dec bx
cmp WORD PTR [bx],16
jne NotMark16 ;brif markId != 16
cmp ax,opStLineInput
je InpMarkLoop ;brif not INPUT #n
jmp SHORT InpExit ;If INPUT #n, pcode is already complete
NotMark16:
or di,[bx]
DbAssertRel di,b,16,CP,<Invalid markId in CgInput>
jmp SHORT InpMarkLoop
;di = bit mask (built by ORing markIds)
;ax = opcode
;
InpMarkLoopDone:
cmp ax,opStLineInput
jne NotLineInput
call Emit16_AX ;emit opcode
push di ;emit bit mask
call Emit16
jmp SHORT InpExit
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -