📄 txtload.asm
字号:
push si ;pass search start text offset
PUSHI ax,<CODEOFFSET tOpProcHdr>
call TxtFindNextOp ;ax=txt offset to next opcode from list
xchg di,ax ;di=txt offset
mov ax,si ;pass search start text offset in ax
call TxtSkipOp ;ax = offset to opcode after si
cmp ax,di
je SameOp ;brif this opcode is in list of
;opcodes which could be deleted
;some opcode not found in tOpProcHdr is on this line,
;remember that we can't delete this line.
mov [otxLastBol],UNDEFINED
SameOp:
mov al,[opIndex] ;al = id of previous opcode
cmp al,PROCHDR_opStRem
jae GotRem ;brif REM or bol opcode
;current opcode is opStDefType, op_Static, or op_Dynamic, delete it.
push ax ;save id of previous opcode
push di ;pass ptr beyond opcode to be deleted
push si ;pass ptr to opcode to be deleted
call TxtMoveDown ;delete current opcode
pop ax ;restore al = id of previous opcode
mov [fDeleted],1 ;remember that something on this
; line has been deleted
mov di,si ;otxCur remains unchanged for next
; iteration of loop (because we
; deleted the opcode)
cmp al,PROCHDR_op_Dynamic
jne NotDyn ;brif not $DYNAMIC
mov [fProcDyn],1
NotDyn:
cmp al,PROCHDR_op_Static
jne ChkNextOp
mov [fProcDyn],FALSE
jmp SHORT ChkNextOp
;al = PROCHDR_xxx for current opcode (we know its a REM or Begin Of Line opcode)
GotRem:
cmp al,PROCHDR_opBolMin
jae ChkNextOp ;brif opcode isnt opQuoteRem or opStRem
lea dx,[si+6] ;dx = otxCur + 6
cmp di,dx
jbe ChkNextOp ;brif REM has no text after it (kill it)
;REM has significant text after it - can't delete it
mov [otxLastBol],UNDEFINED ;remember we can't delete this line
;Now test the opcode after this one
ChkNextOp:
cmp [txtFindIndex],PROCHDR_opBolMin
jb SqNext
;next opcode is an opBol or opBolSp or opEot
cmp [otxLastBol],UNDEFINED
je SqNoDel ;brif we can't delete this line
cmp [fDeleted],FALSE
je SqNoDel ;brif some opcodes on this line has
;not been deleted
cmp al,PROCHDR_opBolMin
jae SqNoDel
;we have deleted all opcodes on this line, delete opBol as well.
push word ptr [TxtFindIndex] ;preserve index of last TxtFind call
push [otxLastBol]
push di
call TxtDelete
mov di,[otxLastBol]
pop ax
mov [TxtFindIndex],al ;restore TxtFindIndex for last TxtFind
; call prior to TxtDelete
SqNoDel:
mov [fDeleted],FALSE ;so far, we've deleted nothing on line
mov [otxLastBol],di ;remember where last start of line
; was so we can delete it later if
; nothing significant is on the line
SqNext:
mov dl,[txtFindIndex]
mov si,di ;advance to next op (otxCur = otxNext)
cmp dl,PROCHDR_opEndProg
jae SqExit ;brif end of table
jmp SqLoop
SqExit:
cEnd
;*************************************************************
; boolean NEAR LoadEnterProc(otxProcDef)
; Purpose:
; Called during ASCII Load when we encounter a SUB or FUNCTION
; statement. SUB/FUNCTION definition line has already been emitted.
; Insert synthetically generated DEFxxx statements to make this
; text table in the same state as the module's table where the
; SUB/FUNCTION statement was seen.
;
; Entry:
; procedure's text table is active
; otxProcDef = where we were in module's text table when the procedure
; definition was seen. We need this so we can update
; linked lists which thread through the module's text table.
;
; Exit:
; modifies ps.bdpDst
; grs.fDirect = FALSE
; If out-of-memory,
; returns 0 (FALSE),
; text table which generated OM error is active.
; else
; ax is non-zero
; procedure's text table is active
; condition codes set based on value in ax
;
;*************************************************************
;.errnz ET_SD - ET_I2 - 4 ;code assumes ET_I2...ET_SD
cProc LoadEnterProc,<PUBLIC,NEAR>,<si,di>
parmW otxProcDef
localW oPrsProc
localW otxStartRem
localW otxStartBlank
localW otxPrev
localB prevType
localB fInRemBlock
cBegin
mov ax,[grs.GRS_oPrsCur]
mov [oPrsProc],ax ;remember which proc we just entered
mov si,[txdCur.TXD_bdlText_cbLogical]
;si = current size of text table
; before synthetic code emitted
SetStartOtx ax ;ax = start of text
mov bx,dataOFFSET tEtTemp
call OtxDefType ;fill tEtTemp with default types
; i.e. ET_R4 for all letters
;If we've seen a $DYNAMIC more recently than a $STATIC before
;place where this procedure occurred in source file,
;emit a $DYNAMIC at start of procedure's text table
FLoadActive
je NotLoading ;brif being called for an edit, not load
SetStartOtx ax ;ax = start of text
mov dh,al ;old state was $STATIC
mov dl,[fDynArrays] ;dl = new state ($STATIC or $DYNAMIC)
mov [fDynArraysMod],dl ;save so LoadExitProc can restore
call InsertDynDiff
je J1_LentEx ;return FALSE if out-of-memory error
NotLoading:
;emit opStDefType opcodes which represent text table's initial state.
PUSHI ax,<dataOFFSET tEtTemp>
PUSHI ax,<dataOFFSET ps.PS_tEtCur>
SetStartOtx ax ;ax = start of text
call InsertEtDiff
je J1_LentEx ;return FALSE if out-of-memory error
neg si
add si,[txdCur.TXD_bdlText_cbLogical]
;si = txdCur.bdlText.cbLogical
; - cbLogical before insertion
; = #bytes of synthetic pcode emitted
push si
mov bx,si
SetStartOtx si ;si = start of text
call TxtInsUpdate ;update line count from 0 to si for
DbAssertRel ax,ne,0,CP,<Unexpected OM error in LoadEnterProc>
pop si ;si = number of bytes inserted
FloadActive ;test if we are currently loading -
; if not then we don't migrate rem's
jne InsOk
J1_LentEx:
jmp LentEx ;return value in ax
InsOk:
;Find the start of a contiguous block of Comments/Bol opcodes
;that precedes the SUB definition. Keep this block with the
;procedure window, not the module window. This allows users
;to put comment blocks before their SUB/FUNCTION definitions
;When done, we'll move the comment block, and delete the blank
;lines preceeding the comment block. If we didn't delete these
;blank lines, several contiguous subs with 1 blank line between
;would leave a huge block of blank lines.
call PrsDeactivate ;make module's txt table active
mov di,[otxLastProc] ;otxCur = otxLastProc
mov [otxStartRem],di
mov [otxStartBlank],di
mov [prevType],PROCHDR_opBol
mov [fInRemBlock],0
LentLoop:
push di ;pass otxCur to TxtFindNextOp
PUSHI ax,<CODEOFFSET tOpProcHdr>
call TxtFindNextOp
cmp dl,PROCHDR_opEot
je LentLoopEx
mov cx,[txdCur.TXD_bdlText_cbLogical]
sub cx,[cbAftMerge] ;cx = otx beyond any MERGEd text
cmp ax,cx
jb NotPastMerge ;brif not beyond MERGE's insertion point
mov dl,PROCHDR_opEndProg ;treat it like reaching opEndProg
xchg ax,cx ;use otx of merge insertion point
NotPastMerge:
mov dh,[prevType] ;dh = txtFindIndex for prev iteration
mov [prevType],dl ;dl=type of cur opcode, dh=type of prev
push dx
xchg di,ax ;update di = otxCur, ax = otxPrev
mov [otxPrev],ax
call TxtSkipOp ;ax = otx beyond opcode otxPrev
pop dx ;restore dl=type of cur, dh=type of prev
cmp ax,di
mov ax,di ;setup for branch to StartBlankBlock
jne StartBlankBlock ;brif next opcode wasn't in tOpProcHdr
cmp dh,PROCHDR_opBolInclude
jae StartBlankBlock ;brif last line came from $INCLUDE file
cmp dl,PROCHDR_opBolMin
jb InCommentBlk ;brif current op isn't a BOL, bolSp, or
; opEndProg opcode
cmp dh,PROCHDR_opBolMin ;check type of previous opcode
jb InCommentBlk ;brif not looking at blank line
;We now know that di points to opBol that terminates a blank line
;If any non-blank lines have been seen since the last blank line,
;reset the start of the blank line block.
cmp [fInRemBlock],0
je StartRemBlock ;brif not start of new block of blanks
mov ax,[otxPrev] ;ax points to start of blank line
;we saw blank line - don't include it with SUB's comment header block
; but include it in block of leading blank lines to be deleted.
; ax either points to start of blank line, or within line that is to
; remain at module level.
;
StartBlankBlock:
mov [fInRemBlock],0
mov [otxStartBlank],ax ;reset start of blank line block
;Found an opcode not in tOpProcHdr, or a blank line.
;di points to next opcode found which was in table (di > ax).
;
StartRemBlock:
mov [otxStartRem],di ;otxStartRem = otxCur
jmp SHORT LentNext
InCommentBlk:
mov [fInRemBlock],1 ;causes any subsequent blank lines
; to reset otxStartBlank
LentNext:
cmp [prevType],PROCHDR_opEndProg
jb LentLoop ;brif end of text table
;[otxStartRem] points to 1st opcode before opStSub which could be
; included with SUB. For example, if pcode was:
; opBol opStPrint opQuoteRem
; opBol opRem
; opBol opStSub
; otxStartRem would point to the opQuoteRem opcode, meaning the 2nd
; line should be included with the SUB.
; Move otxStartRem to the start of the next line.
;
LentLoopEx:
push [otxStartBlank] ; push otx arg.
call OtxBolNext0 ;ax points to next opBolxxx if ax
mov [otxStartBlank],ax ; doesn't currently point to opBolxxx
push [otxStartRem] ; push otx arg.
call OtxBolNext0 ;ax points to next opBolxxx if ax
mov [otxStartRem],ax ; doesn't currently point to opBolxxx
mov di,[otxProcDef]
sub di,ax ;di = cbMove (otxProcDef - otxStartRem)
je NoMove ;brif there is any text to be moved
; move cbMove(di) bytes from module's to proc's text table
; Start by making sure there is room for temp buffer & in proc's text table
;
push [oPrsProc]
call PrsActivateCP ;make new proc's txt table active
push di ;pass cbMove
call TxtFree ;make sure there's room in prs txt tbl
je JE1_LentEx ;brif out-of-memory error
call PrsDeactivate ;make module's txt table active
;Move pcode from module's text table to bdlScrap [8]
; CALL TxtCopyScrap(otxStartRem, StartOtx, di, TRUE) [8]
push [otxStartRem] ;pass otx for start of move
SetStartOtx ax ;[39]ax = StartOtx
push ax ;copy to start of scrap. 0 offset
push di ;pass cbMove
push sp ;push TRUE so text will be deleted
; from text table
call TxtCopyScrap ;move bytes from txdCur to bdlScrap
JE1_LentEx:
DJMP je LentEx ;return FALSE if out-of-memory
push [oPrsProc]
call PrsActivateCP ;make new proc's txt table active
;note that we already called TxtFree to ensure we have enough memory
;so no error is possible.
call TxtInsScrap ;insert bdlScrap in txdCur @ si
mov bx,di ;bx = cbMove
add bx,si ;bx = offset beyond pcode insertion
call TxtInsUpdate ;update line count for inserted lines
DbAssertRel ax,ne,0,CP,<Unexpected OM error 2 in LoadEnterProc>
;squeeze all $DYNAMIC, $STATIC and DEFxxx statements out
;of block copied from module. They are redundant after
;calling InsertEtDiff and InsertDynDiff
call SqueezeDefs ;takes parm in si
NoMove:
call PrsDeactivate ;make module's txt table active
;Delete redundant synthetic DEFxxx statments generated by last LoadExitProc()
;if no user-generated statements were loaded in between.
;If we didn't do this, each time SOME programs are Ascii loaded and saved
;and they contain one or more blank lines between subs, and so
;they grow by the introduction of these redundant DEFtype statements.
;
mov ax,[otxDefEnd]
cmp ax,[otxStartBlank]
jne NoDeadDefTypes ;brif non-synthetic lines exist
; between end of synthetic lines and
; start of leading blank lines
mov ax,[otxDefStart]
mov [otxStartBlank],ax ;else delete synthetic ones
NoDeadDefTypes:
;Now delete blank lines that preceeded the comment block.
mov ax,[otxStartBlank]
mov [otxLastProc],ax
push [otxUpdLinks] ;pass otxUpdLinks to UpdateLinks
push ax ;pass otxLastProc to UpdateLinks
;NOTE: parms to UpdateLinks are on stack
push ax ;pass start of block to delete
push [otxStartRem] ;pass end of block to delete
call TxtDelete ;delete blank lines from mrs text table
call UpdateLinks ;update linked lists which thread
; through module's pcode up to where
; SUB/FUNCTION line was encountered
DbChk TxdOps ;check for bad linked lists through
; pcode, bad opcodes, etc.
;save current def type state so we can bring module
;back up to date at LoadExitProc (if any DEFxxx stmts occur
;within the procedure being loaded)
mov ax,[otxLastProc] ;text offset for new end of module
mov bx,dataOFFSET tEtTemp
call OtxDefType ;fill tEtTemp with default types
; at end of module
mov [otxUpdLinks],StartOtx ;next UpdateLinks will start at
; start of new proc
push [oPrsProc]
call PrsActivateCP ;make new proc's txt table active
;Tell AsciiMerge that we've changed text tables, and
;where to insert next line in the procedure's text table
mov ax,[txdCur.TXD_bdlText_cbLogical]
sub ax,CB_EMPTY_TEXT - StartOtx ;ax = offset to opEndProg
mov [otxNewInsert],ax
DbAssertRel ax,ne,0,CP,<LoadEnterProc: return value zero>
LentEx:
mov [ps.PS_bdpDst.BDP_cbLogical],0 ;release temp buffer
or ax,ax ;set condition codes for caller
cEnd
;*************************************************************
; boolean NEAR LoadExitProc()
; Purpose:
; Called during ASCII Load when we encounter an END SUB or
; END FUNCTION statement.
;
; Entry:
; procedure's text table is active
;
; Exit:
; If out-of-memory
; returns psw.c set
; else
; ax = otx where next stmt should be inserted in module's
; text table
; module's text table is active
;
;*************************************************************
PUBLIC LoadExitProc
LoadExitProc PROC NEAR
push si ;save caller's si
push [otxUpdLinks]
push [txdCur.TXD_bdlText_cbLogical]
call UpdateLinks ;update linked lists which thread
; through procedure's pcode
DbChk TxdOps ;check for bad linked lists through
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -