📄 lsmain.asm
字号:
; in the buffer, which is large enough for all the nodes that could
; be emitted by a single dispatch. Any dispatches that could require
; more than this call GrowBdNodes themselves.
; The outer loop is the only place during Stage1 which
; grows bdNodes, which is the only time heap movement can
; occur. When it does this, it fixes up ES and DI.
;
PUBLIC Stg1Loop
Stg1Loop:
DbAssertRel [oNodeTemp],e,0,LIST,<node found on temp stack at Stg1Loop>
;make sure bdNodes > CB_NODES_MIN bytes, updating ES for movement
mov ax,CB_NODES_MIN ;ax = min free we need
add ax,di ;ax = size we need buffer to be
sub ax,[bdNodes.BD_cbLogical] ;ax = free space
jnc GetRoom ;brif not enough free bytes exist
GotRoom:
cmp si,[otxLsCursorTmp]
jae SetNdLsCursor ;brif caller wants to know column
; of token for the last opcode listed.
; Control returns to SetNdRet.
SetNdRet:
lods WORD PTR es:[si] ;ax = opcode
cmp [txdCur.TXD_scanState],SS_EXECUTE
jne GotOpcode
;convert to opcode since text table's scan state is SS_EXECUTE
xchg bx,ax ;bx = executor's adr
GetSegAddr CODE ;ax = adr of CODE seg
mov ds,ax ;ds = adr of CODE seg
mov ax,[bx-2] ;ax = executor's opcode
push ss
pop ds ;restore ds = DGROUP
GotOpcode:
mov [opList],ax ;save for individual list rules
and ah,HIGH OPCODE_MASK ;upper bits sometimes used for operands
mov bx,ax ;bx = opcode
shl bx,1 ;bx = opcode * 2
mov [opList2],bx ;save index for individual list rules
jmp [mpOpLister + bx] ;dispatch to lister function
;function will branch back to Stg1Loop
; or Stage2
;Some serious error has occured while listing (like out-of-memory)
; return error code
;
ListErrExit:
mov ax,UNDEFINED ;return error result
jmp ListLineExit ;return ax
;!!!WARNING!!! No heap movement can occur during Stage2, because
; we convert all bdNode offsets to pointers while reversing the direction
; of the list.
;This is not a problem in EB since the node buffer is static.
;
; Stage2:
; Taking the tree which was built in step1, do a post-order traversal
; dispatching to a special function for each node type. Each of these
; functions appends text to the current output line.
; global register conventions:
;
; Stage2Inc is branched to when the terminating bol is for an included
; line. In this case, otxListNextInc has already been set.
;
;
PUBLIC Stage2, Stage2Inc
Stage2:
call GrowBdNodes ;this test will ensure that we
; have not written past end of buffer
mov [otxListNextInc],si ;save it for caller
Stage2Inc:
mov [otxListNext],si ;save it for caller
;If there was a node that contained token of interest, replace
;the node type with LNT_CURSOR (similar to a break-point), so
;we don't have to compare at every stage2 dispatch.
mov bx,[ndLsCursor]
inc bx
je NoNdLsCursor ;brif line doesn't contain otxLsCursor
add bx,[bdNodes.BD_pb] ;convert offset to ptr
mov al,LNT_CURSOR
xchg [bx+LN_type-1],al
mov [lnTypeFindSave],al
NoNdLsCursor:
mov di,[pbdDst] ;di points to destination buffer dsc
mov ax,[di.BD_cbLogical] ;ax = max size of buffer
mov di,[di.BD_pb] ;di points to destination buffer
mov [colLastTok],di
mov [colLastLine],di
add ax,di ;ax points beyond end of buffer
sub ax,42d ;42 bytes is enough for an id, reserved
; word, number, or char[s] node
; Spaces/String/Col nodes check
; for themselves
DJMP jc ListDstFull ;brif dst doesn't even have 42 bytes
mov [pbDstWarning],ax
mov si,[oNodeRoot] ;si = offset to root node
or si,si
je Stg2Done ;brif nothing to list
sub ax,ax ;prev node = NULL
push ax ;this will stop EndOfListLoop
;si=offset to start of list of nodes, to be listed in reverse order, i.e. last
; node in list will be listed first, start of list will be listed last.
FindEndOfList:
sub cx,cx ;prev node = NULL
;si = offset to current node,
;cx points to previous node (if start of list, cx = 0),
;Traverse si's list to the end, then start listing nodes in reverse order
;
EndOfListLoop:
add si,[bdNodes.BD_pb] ;convert offset to ptr
xchg cx,LN_sib[si] ;cx = offset to next node (if any)
;swap ptr from prev->next to next->prev
; so we can work our way back
jcxz ListNodeSi ;brif we're at the end-of-list
xchg cx,si ;cx points to prev node
;si = offset to current node
jmp SHORT EndOfListLoop
;si points to last node in list, list it, then list all the nodes which
; came before it in the linked-list
;di points to destination of next ASCII byte to be listed
;
DbPub ListNodeSi
ListNodeSi:
cmp di,[pbDstWarning]
DJMP jae ListDstFull ;brif destination buf almost full
mov bl,LN_type[si] ;bx = node type
DispNodeBl:
sub bh,bh ;bh = 0
jmp [mpNodeLister + bx] ;dispatch to lister function
;function will branch back to Stg2Cont
;si still points to node which was just listed.
; now, advance to previous sibling to be listed and list it.
;
DbPub Stg2Cont
Stg2Cont:
mov si,LN_sib[si] ;si points to left sibling of node
FLoadActive
jne ChkLineWrap ;see if _CrLf needs to be inserted
; for a line > 250 chars long
; (so BASCOM can read it)
; jumps back to either LineWrapRet
LineWrapRet:
or si,si ; we just listed (0 if start-of-list)
jne ListNodeSi ;brif not at start of list yet
EndOfList:
pop si ;recover node stacked by ListChildList:
or si,si ;test for stopper pushed just before
; FindEndOfList:
jne Stg2Cont ;brif still more to list
;else, we've reached the 0 stopper
; pushed by ListChildList
;NOTE: This is branched to by StaticBufFull
Stg2Done:
sub ch,ch ;clear high byte
mov cl,[fGotBol] ;cl = number of leading spaces or
;UNDEFINED.
inc cl ;check for UNDEFINED
jz NoLeadingSpc ;return 0 if no leading spaces
dec cl ;return number of leading spaces
NoLeadingSpc:
;Many opcode listers leave a space at the end, in case they are
;followed by something else. If the last char in the line is
;a space, and the line does not contain only white space,
;eliminate the last space, and then 0-byte terminate the line.
mov ax,di ;ax points beyond last destination byte
mov bx,[pbdDst]
sub ax,[bx.BD_pb] ;ax = number bytes listed to buffer
je NoTrailSpc ;brif 0 bytes listed
cmp BYTE PTR -1[di],' '
jne NoTrailSpc ;brif last byte is not " "
cmp ax,cx ;is the line blank?
je NoTrailSpc ;brif so, preserve trailing space
dec di ;eliminate trailing space
dec ax ;decrement return value (byte count)
NoTrailSpc:
mov BYTE PTR [di],0 ;0-byte terminate text
ListLineExit: ;return ax
push cx ;save leading space count
push ax ;save byte count
mov bx,[pbdDst]
call SetLsCursor ;dx = col equivalent to otxLsCursor
pop ax ;ax = byte count
pop cx ;cx = leading space count
mov [cLeadingSpaces],cl ;record leading space count in
; static
;NOTE: we can't release space held by bdNodes, or else we risk
;causing an out-of-memory error while trying to draw the debug
;screen, which would be an infinite loop. If necessary, we could
;reset it in ParseNewInit
;;; mov [bdNodes.BD_cbLogical],0 ;Reset the buffer which holds nodes
cEnd ListLine
;******
;NOTE
; Code below this point accesses variables on ListLine's BP frame.
; Don't insert any CEND macros between here and the next CEND.
;
;******
; ListDstFull
;
;Branched to when destination buffer is almost full
;Grows destination buffer (if possible) and tries again from the start
;of ListLine. We have to do it from the start, since no heap movement
;can occur during stage 2 (for speed of typical case).
;
;For RELEASE code in EB we just assume that when we get here it must be
;
ListDstFullDS:
ListDstFull:
mov sp,[spSave]
; destination buffer
mov bx,[pbdDst] ;bx points to destination buf desc.
mov ax,[bx.BD_cbLogical]
cmp ax,80d
jb StaticBufFull
add ax,128d ;try 128 bytes more
push bx ;pass pbdDst to BdRealloc
push ax ;pass cbNew to BdRealloc
call TxtGrowPsSrcEmScratch ;make sure bdEmScratch and
;ps.bdpSrc both get updated
or ax,ax
jne NotOm ;brif not out-of-memory
jmp ListErrExit ;return UNDEFINED
NotOm:
jmp ListLineRestart
StaticBufFull:
jmp Stg2Done ;0-terminate line and return to caller
;We're doing an ASCII Save
;see if _<space><CR><LF> needs to be emitted for a line > 250 chars long
; (so BASCOM can read it)
; si points to node for next token to list
; di = column we're about to write next token to
; [colLastTok] = column we wrote last token to (initially 0)
; [colLastLine] = column which began last physical line (initially 0)
;
DbPub ChkLineWrap
ChkLineWrap:
.errnz LNT_CHAR_TOK - 0
.errnz LNT_STR - 2
.errnz LNT_ENSTR - 4
.errnz LNT_CSSTR - 6
.errnz LNT_LITSTR - 8
;The following node types start lexical tokens
.errnz LNT_ONAM - 10
.errnz LNT_LIST - 12
.errnz LNT_RW - 14
.errnz LNT_SPACES - 16
.errnz LNT_NUM - 18
.errnz LNT_COL - 20
.errnz LNT_CHAR - 22
.errnz LNT_CURSOR - 24
or si,si
je EndOfList1 ;brif end of linked list of nodes
cmp LN_type[si],LNT_ONAM
jb J1_LineWrapRet ;brif this node does not necessarily
; begin a lexical token. For example:
; "string" = 3 nodes: char,str,char
; X$ = 2 nodes: oNam,char
EndOfList1:
mov [colLastTok],di
J1_LineWrapRet:
jmp LineWrapRet
;***************************************************************************
; ChkDstFull
; Purpose:
; Make sure there's room in destination buffer for a new item.
; If pbdDst.cbLogical < 80, buffer is static and cannot be grown,
; just truncate listing (used by WatchName)
; Entry:
; di = current pointer into destination buffer
; cx = number new bytes needed in destination buffer
; [18]for EB ds need not point to DGROUP. If there is no room then DS
; is restored to DGROUP before restarting ListLine.
; Exit:
; If there's room, this function returns, else, ListLine
; is restarted after growing buffer.
; Preserves:
; all registers except flags and ax
;
;***************************************************************************
assumes DS,NOTHING
DbPub ChkDstFull
ChkDstFull PROC NEAR
mov ax,di ;ax = current dest ptr
add ax,cx ;ax = result dest ptr (end of string)
jc ListDstFullDS ;brif wrapped past FFFF
; (buf too small)
cmp ax,[pbDstWarning]
jae ListDstFullDS ;brif string too big -
; grow dst buffer
ret
ChkDstFull ENDP
assumes DS,DGROUP
;***************************************************************************
; GrowBdNodes
; Purpose:
; Grow the temporary buffer filled by Stg1Loop if necessary.
; Entry:
; di = current offset into bdNodes buffer
; Exit:
; ax = zero if out-of-memory (or out of static buffer space),
; condition codes set accordingly
; es = segment adr of current text table
; Preserves: cx
;
;***************************************************************************
PUBLIC GrowBdNodes
GrowBdNodes PROC NEAR
mov ax,CB_NODES_MIN ;ax = min free we need
add ax,di ;ax = size we need buffer to be
sub ax,[bdNodes.BD_cbLogical] ;ax = free space
jc GrowExit ;brif enough free bytes exist
;ax is nonzero, psw.ZR is FALSE
push cx ;save caller's cx
PUSHI ax,<dataOFFSET bdNodes>
PUSHI ax,CB_NODES_GROW
call BdGrow
GETSEG es,[txdCur.TXD_bdlText_seg],,<SIZE,LOAD> ;[4]
;es = segment for current text tbl
pop cx ;restore caller's cx
or ax,ax ;test BdGrow's return value
GrowExit:
ret
GrowBdNodes ENDP
sEnd LIST
sBegin DATA
mpNodeLister LABEL WORD
DW LISTOFFSET ListCharsNode
DW LISTOFFSET ListStrNode
DW LISTOFFSET ListEnStrNode
DW LISTOFFSET ListCsStrNode
DW LISTOFFSET ListLitStrNode
DW LISTOFFSET ListONamNode
DW LISTOFFSET ListChildList
DW LISTOFFSET ListRwNode
DW LISTOFFSET ListSpacesNode
DW LISTOFFSET ListNumNode
DW LISTOFFSET ListColNode
DW LISTOFFSET ListCharsNode
DW LISTOFFSET ListCursorNode
.errnz LNT_CHAR_TOK - 0
.errnz LNT_STR - 2
.errnz LNT_ENSTR - 4
.errnz LNT_CSSTR - 6
.errnz LNT_LITSTR - 8
.errnz LNT_ONAM - 10
.errnz LNT_LIST - 12
.errnz LNT_RW - 14
.errnz LNT_SPACES - 16
.errnz LNT_NUM - 18
.errnz LNT_COL - 20
.errnz LNT_CHAR - 22
.errnz LNT_CURSOR - 24
sEnd DATA
sBegin LIST
assumes CS,LIST
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -