Class STM represents one assembler statement. Each statement will be
StmExecute detects new current section (when AUTOSEGMENT=ON), autoalignment (when AUTOALIGN=ON)
and sets Stm.Section, Stm.AlignBytes. New section offset is autoaligned and put to Stm.Offset
, which is an offset of symbol created with this statement. Data emirted by the statement
are stored to Stm.EmitBuffer.
StmFlush updates new section's Sss.Org with Stm.AlignBytes
plus the size of emitted data.
Then it copies alignment stuff and the contents of Stm.EmitBuffer to its Sss.EmitBuffer.
It is also responsible for updating Pgm.CurrentSect from Stm.Section.
EUROASM NOWARN=2101
stm PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32
INCLUDEHEAD euroasm.htm, \ Interface (structures, symbols and macros) of other modules used in this source.
chunk.htm,ctx.htm,dict.htm,ea.htm,eaopt.htm,exp.htm,ii.htm,lst.htm,msg.htm,pgm.htm, \
pgmopt.htm,reloc.htm,sss.htm,sym.htm,var.htm
stm HEAD ; Start of module interface.
STM STRUC
.LabelPtr D D ; Pointer to the label field, including the possible [].
.LabelSize D D ; Label size without trailing colon(s).
.Status D D ; Binary properties of the statement in StmEnc encoding.
.Flags D D ; Temporary parsing miscellaneous flags in StmEncTemp encoding.
; +10h.
.Prefix1Ptr D D ; Pointer to the machine prefix field.
.Prefix1Size D D ; Size of the machine prefix.
.Prefix1Data D D ; Data value
.Prefix2Ptr D D ; Pointer to the machine prefix field.
; +20h.
.Prefix2Size D D ; Size of the machine prefix.
.Prefix2Data D D ; Data value
.Prefix3Ptr D D ; Pointer to the machine prefix field.
.Prefix3Size D D ; Size of the machine prefix.
; +30h.
.Prefix3Data D D ; Data value
.Prefix4Ptr D D ; Pointer to the machine prefix field.
.Prefix4Size D D ; Size of the machine prefix.
.Prefix4Data D D ; Data value
; +40h.
.NrOfPrefixes D D ; Number of machine prefixes (0..4).
.NrOfOrdinals D D ; Number of ordinal operands (0..*).
.NrOfKeys D D ; Number of keyword operands (0..*).
.ChunkPtr D D ; Pointer to the chunk which .LinePtr belongs to, or 0.
; +50h.
.LinePtr D D ; Pointer to the 1st physical line of this statement.
.LineEnd D D ; Pointer behind the last of physical lines which create this statement.
.LineNext D D ; Pointer to the physical line of next following statement, or 0 if = .LineEnd.
.ChunkNext D D ; Pointer to the chunk which .LineNext belongs to, or 0.
; +60h.
.OperationPtr D D ; Pointer to the operation field of the statement.
.OperationSize D D ; Size of the operation field (nr of characters in ii mnemonic)
.OperationData D D ; Case stmPseudoOperation: Dict.Data. Case stmMacroOperation: ^MAC. Case stmIntelOperatoion: iiHandler.
.OrdBuffer D D ; ^BUFFER of 2*DDs keeping ordinal operands (Ptr+Size pairs).
; +70h.
.KeyBuffer D D ; ^BUFFER of 4*DDs keeping keyword operands (NamePtr,NameSize,ValuePtr,ValueSize).
.ExpBuffer D D ; ^BUFFER which holds %variable-expanded physical line.
.SrcBuffer D D ; ^BUFFER of unexpanded source code with machine/markup comment stripped off.
.EmitBuffer D D ; ^BUFFER of emitted assembled data, without autoalignment. Empty on BSS reservation.
; +80h.
.MsgBuffer D D ; ^BUFFER of formated messages, including the leading '|' and CR+LF.
.RelocBuffer D D ; ^BUFFER of 0 or more RELOC records of this statement.
.Program D D ; ^PGM. Current program.
.CtxStatusAll D D ; CTX.Status logical ORed from all contexts on CtxStack before the Stm is executed.
; Following members together with .Label are used for creating a symbol.
; They must be set prior to calling SymCreate from Pseudohandler.
; +90h:
.OffsetLow D D ; bits 0..31 symbol (autoaligned) offset from begining of segment (not from section).
.OffsetHigh D D ; bits 32..63. Stm.Offset is set in instruction handlers from new section .Org.
.Section D D ; Ptr to SSS (sssSect) where it was declared in, or 0 for constants.
.Size D D ; Symbol.Size. Length of emitted data in .EmitBuffer or of BSS reservation.
; +A0h.
.AlignBytes D D ; Signed number of autoalignment bytes, depending on AUTOALIGN=YES or
; explicit ALIGN= operand of the statement. Alignment value is set in instruction handler.
; It is not used in PseudoALIGN (explicit alignment).
ENDSTRUC STM
stmTypeMask + stmPropMask are kept synchronized with
symTypeMask + symPropMask in symbol encoding SymEnc
. They are used in SymCreate.; Statement type if a symbol was defined with the statement. stmTypeMask = 0x0000_00FF ; Uppercase letter BUWDQTPISNA?. Synchronized with symTypeMask. ; Statement properties. stm1 = 0x0000_0100 ; Difference between PROC/PROC1, INCLUDE(HEAD)/INCLUDE(HEAD)1. stmIncludeAny = 0x0000_0200 ; Operation is INCLUDE*. stmIncludeHead = 0x0000_0400 ; Difference between INCLUDE/INCLUDEHEAD, INCLUDE1/INCLUDEHEAD1. stmIncludeBin = 0x0000_0800 ; Difference between INCLUDEBIN/INCLUDE. stmSpecialChunk = 0x0000_1000 ; Chunk of this stm is Orig/OrigBin/Resolved/Bin/Error. ; Symbol properties if symbol were defined with the statement. Synchronized with symPropMask stmLabelIsPublic = 0x0008_0000 ; EQU symGlobalRef. Two or more colons follow the label. stmIncluded = 0x0010_0000 ; EQU symIncluded. Statement/symbol was declared in included source chunk. stmProc = 0x0020_0000 ; EQU symProc. Statement is PROC or PROC1. stmNear = 0x0040_0000 ; EQU symNear. Symbol defined with this statement has DIST=NEAR. stmFar = 0x0080_0000 ; EQU symFar. Symbol defined with this statement has DIST=FAR. stmPropMask = stmIncluded|stmProc|stmNear|stmFar ; Parser properties. stmLabelPresent = 0x0100_0000 ; LabelPtr is valid. stmPrefixPresent = 0x0200_0000 ; At least one instruction prefix was used in statement. stmOperationPresent = 0x0400_0000 ; OperationPtr is valid. stmPseudoBlock = 0x0800_0000 ; 2nd field is pseudooperation. See StmParsePcPseudo. stmPseudoOperation = 0x1000_0000 ; Operation field recognized as pseudooperation. stmMacroOperation = 0x2000_0000 ; Operation filed recognized as macro. stmIntelOperation = 0x4000_0000 ; Operation field recognized as machine instruction. stmQueried = 0x8000_0000 ; Unary-attribute operation pending in ExpEval.
stmtLabelParsed = 0x0000_0001 ; Label field was already parsed. stmtExpPrototype = 0x0000_0002 ; Parsed statement is in ctxMACRO+ctxExpansion, it may be a prototype. stmtOperationParsed = 0x0000_0004 ; Operation field was already parsed. stmtNotBSS = 0x0000_0008 ; This D statement defines initialized data in at least one its operands. stmtSETany = 0x0000_0010 ; Operation is %SET/A/B/C/U/E/2/S/L but not %SETX. Label not expanded. stmtSETLorS = 0x0000_0020 ; Operation is %SETL or %SETS, no field is expanded. stmtWithPath = 0x0000_0040 ; Included filename contains path. stmtWildcarded = 0x0000_0080 ; Included filename contains * or ?. stmtAtLeast1 = 0x0000_0100 ; At least one file was included. stmt2ndPass = 0x0000_0200 ; Statement is parsed in 2nd pass, %var and line-continuation expanded. stmtProgram = 0x0000_1000 ; Statement is pseudoinstruction PROGRAM. stmtOutFile = 0x0000_2000 ; Current field is keyword OUTFILE=. stmtKeepSect = 0x0000_8000 ; Do not update PGM.CurrentSect from STM.Section in StmFlush.
StmInStruc %MACRO Stm, Target
TESTD [%Stm+STM.CtxStatusAll],ctxSTRUC
Msg cc=NZ,'7125' ; This instruction is not allowed in STRUC definition.
JNZ %Target
%ENDMACRO StmInStruc
ENDHEAD stm ; End of module interface.
StmCreate Procedure Stm
MOV EBX,[%Stm]
SUB EAX,EAX
MOV EDI,EBX
MOV ECX,SIZE#STM / 4
REP STOSD
Invoke EaBufferReserve::, StmCreate
MOV [EBX+STM.OrdBuffer],EAX
Invoke EaBufferReserve::, StmCreate
MOV [EBX+STM.KeyBuffer],EAX
Invoke EaBufferReserve::, StmCreate
MOV [EBX+STM.ExpBuffer],EAX
Invoke EaBufferReserve::, StmCreate
MOV [EBX+STM.EmitBuffer],EAX
Invoke EaBufferReserve::, StmCreate
MOV [EBX+STM.MsgBuffer],EAX
Invoke EaBufferReserve::, StmCreate
MOV [EBX+STM.RelocBuffer],EAX
Invoke EaBufferReserve::, StmCreate
MOV [EBX+STM.SrcBuffer],EAX
EndProcedure StmCreate
StmClean Procedure Stm
MOV EBX,[%Stm]
PUSHD [EBX+STM.OrdBuffer]
PUSHD [EBX+STM.KeyBuffer]
PUSHD [EBX+STM.ExpBuffer]
PUSHD [EBX+STM.EmitBuffer]
PUSHD [EBX+STM.MsgBuffer]
PUSHD [EBX+STM.RelocBuffer]
PUSHD [EBX+STM.SrcBuffer]
SUB EAX,EAX
MOV ECX,SIZE#STM / 4
MOV EDI,EBX
REP STOSD
POPD [EBX+STM.SrcBuffer]
POPD [EBX+STM.RelocBuffer]
POPD [EBX+STM.MsgBuffer]
POPD [EBX+STM.EmitBuffer]
POPD [EBX+STM.ExpBuffer]
POPD [EBX+STM.KeyBuffer]
POPD [EBX+STM.OrdBuffer]
BufferClear [EBX+STM.OrdBuffer]
BufferClear [EBX+STM.KeyBuffer]
BufferClear [EBX+STM.ExpBuffer]
BufferClear [EBX+STM.EmitBuffer]
BufferClear [EBX+STM.RelocBuffer]
BufferClear [EBX+STM.SrcBuffer]
EndProcedure StmClean
StmDestroy Procedure Stm
MOV EDI,[%Stm]
Invoke EaBufferRelease::,[EDI+STM.OrdBuffer]
Invoke EaBufferRelease::,[EDI+STM.KeyBuffer]
Invoke EaBufferRelease::,[EDI+STM.ExpBuffer]
Invoke EaBufferRelease::,[EDI+STM.EmitBuffer]
Invoke EaBufferRelease::,[EDI+STM.MsgBuffer]
Invoke EaBufferRelease::,[EDI+STM.RelocBuffer]
Invoke EaBufferRelease::,[EDI+STM.SrcBuffer]
SUB EAX,EAX
MOV ECX,SIZE#STM / 4
REP STOSD
EndProcedure StmDestroy
Emitting statement (ALIGN, D*, prefix, Intel instruction) will store
the data to Stm.EmitBuffer and relocations to Stm.RelocBuffer.
Section changing instructions (SEGMENT, STRUC, [section]) will set new section to Stm.Section.
Data gathered during execution (Stm.EmitBuffer, Stm.RelocBuffer and Stm.Section)
will be moved to section.EmitBuffer, section.RelocBuffer
and Pgm.CurrentSect later in StmFlush.
StmExecute Procedure Stm
StmExMsgId LocalVar ; MsgId of chunkError.
ErrPar LocalVar Size=8 ; Msg parameter !1S.
MOV EBX,[%Stm]
MOV ECX,[EBX+STM.Program]
JECXZ .05:
MOV [ECX+PGM.CurrentStm],EBX
.05: ; Dispatch by the type of source chunk.
JNSt [EBX+STM.Status],stmSpecialChunk,.22: ; Skip if the Stm is in ordinary source chunk.
; chunkBin and chunkError are executed here. chunkOrig and chunkResolve ignored.
MOV EDX,[EBX+STM.ChunkPtr]
MOV EAX,[EDX+CHUNK.Status]
JNSt EAX,chunkError,.10:
LEA EBX,[%ErrPar] ; Chunk with error message. MsgId and parameter is in the chunk.
MOV ESI,[EDX+CHUNK.Bottom]
MOV ECX,[EDX+CHUNK.Top]
MOV [EBX+0],ESI
SUB ECX,ESI
MOV [EBX+4],ECX
SHR EAX,16
LEA EDI,[%StmExMsgId]
StoD EDI,Size=4
Msg [%StmExMsgId],EBX ; Report chunk error message.
JMP .90:
.10:JNSt EAX,chunkBin,.20:
; INCLUDEBIN chunk. Binary data are in chunk contents. They will be emitted to statement current section.
MOV ESI,[EDX+CHUNK.Bottom]
MOV ECX,[EDX+CHUNK.Top]
SUB ECX,ESI
BufferStore [EBX+STM.EmitBuffer],ESI,ECX
Msg cc=C,'9314',StmExecute ; Allocation error storing to buffer in !1H.
JMP .90:
.20:JSt EAX,chunkOrig|chunkResolved,.90: ; Such chunks contain INCLUDE* which has already been processed.
.22:; Dispatch by the operation gender (none, machine, macro, pseudo).
JSt [EBX+STM.Status],stmPseudoOperation,.PseudoOperation:
JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90: ; Only pseudooperations are executed in noemitting status.
JSt [EBX+STM.Status],stmMacroOperation, .MacroOperation:
JSt [EBX+STM.Status],stmIntelOperation, .IntelOperation:
JNSt [EBX+STM.Status],stmPrefixPresent,.25:
StmInStruc EBX,.90: ; Do not allow prefix inside STRUC block.
.25:Invoke PseudoNoOperation::,EBX ; Empty statement. It has only label and/or machine prefix.
JMP .90:
.IntelOperation: ; Machine instruction. Stm.OperationData contains ptr to handler, e.g. IiMOV::.
StmInStruc EBX,.90: ; Do not allow machine instruction inside STRUC block.
CMPD [EBX+STM.NrOfOrdinals],1
JNA .40:
Invoke StmMultiop?, EBX ; Test if it's multioperand machine instruction (INC*, DEC*, PUSH*, POP*).
JNZ .40:
Invoke IiAssembleMultiop::,EBX
JMP .90:
.40:Invoke IiAssemble::,EBX
JMP .90:
.MacroOperation: ; Macroinstruction. Stm.OperationData is ptr to MAC object,
Invoke MacExpand::,EBX ; which contains MAC.LinePtr to %MACRO statement (prototype) in the mapped source.
JMP .90:
.PseudoOperation: ; Pseudoinstruction. Stm.OperationData contains pseudoinstruction handler. e.g. PseudopcSET::.
Invoke [EBX+STM.OperationData],EBX
.90:EndProcedure StmExecute
STM.ExpBuffer specified with Stm parameter,
preprocessing %variables in the input field will be expanded and suboperated.
No %variable is expanded when the context is not in emitting state.
Stm.Flags:stmtProgram&&stmtOutFile are both set, variable %&
is not expanded but its percent sign is doubled to %%& instead.Stm.Status:stmIncludeAny is set, variable %&
is not expanded but its percent sign is doubled to %%& instead.Stm.Flags:stmtSETany is set.
This flag is reset once it is used.Stm.Flags:stmtSETLorS is set.
This flag is not reset.STM.ExpBuffer is appended with expanded field contents.LinePtr.
FieldPtr FieldEnd
| |
[EBX+STM.%Member]
Stm.ExpBuffer will be appended with text [EBX+STM.LinePtr].StmExpandField Procedure Stm, FieldPtr, FieldEnd StmTmpBuf LocalVar ; Temporary buffer for expansion of%&. Invoke EaBufferReserve::,StmExpandField MOV [%StmTmpBuf],EAX MOV EDX,[%FieldEnd] MOV ESI,[%FieldPtr] MOV ECX,EDX MOV EBX,[%Stm] SUB ECX,ESI JNSt [EBX+STM.Flags],stmtProgram,.10: JNSt [EBX+STM.Flags],stmtOutFile,.10: ; Special case 1. In statements likePROGRAM OUTFILE="file"{%&-10..%&}; variable%&is not expanded here but changed to%%&. JMPS .20: .10:JNSt [EBX+STM.Status],stmIncludeAny, .50: ; Special case 2. In statements likeINCLUDE "file"{%&-10..%&}; variable%&is not expanded here but changed to%%&. .20:CMP ESI,EDX JNB .40: CMPB [ESI],'%%' JNE .30: CMPB [ESI+1],0x26 ; '&'. JNE .30: BufferStore EAX,ESI,1 ;%&detected, store additional % to postpone expansion. .30:BufferStore EAX,ESI,1 ; Copy input to output, one character after another. INC ESI JMP .20: .40:BufferRetrieve EAX LEA EDX,[ESI+ECX] .50:; ESI,ECX alias ESI..EDX is now the prepared input field ready for expansion of %variables. JNSt [EBX+STM.Flags],stmtSETLorS,.60: ; Special case 3. Statements like%Var %SETL %OtherVarare not expanded at all. SUB EDX,ESI BufferStore [EBX+STM.ExpBuffer],ESI,EDX ; Copy input to output without expansion. JMP .90: .60:JNSt [EBX+STM.Flags],stmtSETany,.80: ; Special case 4. In statements like%Var %SET %OtherVarthe first %Var will not be expanded. RstSt [EBX+STM.Flags],stmtSETany ; Clear the flag once used. .70:CMP ESI,EDX JNB .90: LODSB ExpClassify AL TEST AH,expWhiteSpace JNZ .70: ; Skip leading whitespaces. DEC ESI CMP AL,'%%' JNE .80: ; If not the special case 3. MOV EDI,ESI Invoke VarParseName::,EDI,EDX ; Find the end of %Var name to ESI. MOV ECX,ESI SUB ECX,EDI BufferStore [EBX+STM.ExpBuffer],EDI,ECX ; Store nonexpanded %variable name. .80: ; ESI..EDX is the rest of field. Invoke VarExpandField::, ESI,EDX,[EBX+STM.ExpBuffer],-1 ; Expand the rest of field. .90: Invoke EaBufferRelease::,[%StmTmpBuf] EndProcedure StmExpandField
.Program, .Section, .Offset
with current values, although they may be changed later in statement execution.
StmParse Procedure Stm, LinePtr, ChunkPtr
StmPaFlags LocalVar ; Temporary flags prepared for STM.Flags.
StmPaLineEnd LocalVar ; Pointer to the end of expanded statement.
StmPaErrPar LocalVar Size=8 ; Msg parameter !1S.
StmPaOperand LocalVar Size=16 ; Temporary room for construction of operand record.
MOV EBX,[%Stm] ; Ptr to a clean Stm object with buffers allocated.
MOV EAX,[%LinePtr]
.P10: Invoke SrcFetchLine::,EAX,[%ChunkPtr] ; Returns ESI=start of line, EAX=end of line, EDX=chunk.
JC .99: ; Do nothing at the end of source (top of the last chunk).
JZ .P10: ; If the whole line was a machine|markup-comment, fetch the next one.
MOV [EBX+STM.LinePtr],ESI
MOV [EBX+STM.LineEnd],EAX
MOV [EBX+STM.ChunkPtr],EDX
MOV ECX,EAX
Invoke CtxStatusAll::
MOV [EBX+STM.CtxStatusAll],EAX ; Logical sum of all context properties (for simplified detection).
Invoke PgmGetCurrent::
MOV [EBX+STM.Program],EAX
TEST EAX
JZ .P30:
.P20:MOV EDI,[EAX+PGM.CurrentSect]
MOV [EBX+STM.Section],EDI ; Default values of .Section and .Offset may be updated later in StmExecute.
TEST EDI
JZ .P30:
MOV EAX,[EDI+SSS.OrgLow]
MOV [EBX+STM.OffsetLow],EAX
MOV EAX,[EDI+SSS.OrgHigh]
MOV [EBX+STM.OffsetHigh],EAX
.P30: SetSt [Src.Lst.Status::],lstNothingExp ; First assume that STM contains no %variables.
; This flag may be reset later in VarExpand.
SetSt [EBX+STM.Status],stmSpecialChunk ; Assume that the line comes from special chunk and requires special handling.
JSt [EDX+CHUNK.Status],chunkBin|chunkError,.99: ; These data are not parsed.
SUB ECX,ESI
BufferStore [EBX+STM.SrcBuffer],ESI,ECX ; Save the raw source line to listing as is.
JSt [EDX+CHUNK.Status],chunkOrig|chunkOrigBin|chunkResolved,.99: ; These lines are only listed, not executed.
RstSt [EBX+STM.Status],stmSpecialChunk ; Line comes from an ordinary chunk.
JNSt [EDX+CHUNK.Status],chunkIncluded,.F00:
SetSt [EBX+STM.Status],stmIncluded
.F00: ; First pass of horizontal parsing will copy the statement to Stm.ExpBuffer
; with %variables expanded and continuation lines concatenated.
CMP ESI,[EBX+STM.LineEnd]
JNB .99:
LODSB
ExpClassify AL
TEST AH, expWhiteSpace
JNZ .F00: ; Ignore leading spaces.
CMP AL,';' ; Detect double semicolon as line-comment marked..
JNE .F10:
CMP AL,[ESI]
JNE .F10:
SetSt [Src.Lst.Status::],lstNoData ; Do not display the change of section in dump column.
.F10:CMP AL,"%%"
JNE .F20:
DEC ESI
Invoke StmParseSET,EBX,ESI ; Detect %SET* special case and set flags stmtSETany or stmtSETLorS.
INC ESI
.F20:DEC ESI
.F30:MOV EDI,ESI ; At the beginning of a statement field.
Invoke StmParseField,EBX,ESI,[EBX+STM.LineEnd] ; Find the end of statement field.
MOV ECX,EAX ; End of field.
MOV ESI,EAX
SUB ECX,EDI ; Brutto size of the field.
JNSt [EBX+STM.Flags],stmtProgram,.F35: ; Detect special case PROGRAM OUTFILE=.
RstSt [EBX+STM.Flags],stmtOutFile
PUSHAD
XCHG ESI,EDI
StripSpaces ESI,ECX
CMP ECX,15
JB .F33: ; If it's too short to contain keyword OUTFILE="?"[%&].
LODSD
OR EAX,0x20202020 ; Convert to lowercase
CMP EAX,'outf'
JNE .F33:
LODSD
OR EAX,0x20202020 ; Convert to lowercase
CMP EAX,'ile='
.F33:POPAD
JNE .F35:
SetSt [EBX+STM.Flags],stmtOutFile
.F35:Invoke StmExpandField,EBX,EDI,ESI ; Expand %variables to Stm.ExpBuffer.
JSt [EBX+STM.Flags],stmtOperationParsed, .F70: ; Skip when the operation field has already been parsed.
StripSpaces EDI,ECX
JECXZ .F45:
MOV DL,[EDI+ECX-1] ; Terminating character, it might be a colon.
StripColons EDI,ECX
CMP DL,":"
JE .F60: ; If it's terminated with colon, it must be a label or prefix.
; Field is not colon-terminated, it might be a label or prefix or operation.
Invoke DictLookup::, DictPrefixes::, EDI,ECX
JNC .F60: ; If the field is one of CPU instruction prefix.
Invoke DictLookup::, DictPseudo::, EDI,ECX
JNC .F50: ; The field is pseudooperation.
Invoke MacFind::, EDI,ECX
JC .F40:
; Field is a macrooperation, but it may also be an expansion of macro prototype.
Invoke CtxPeek::,ctxExpansion,0
JC .F50:
JNSt [EAX+CTX.Status],ctxMACRO,.F50:
; Parsed statement is macro prototype in ctxExpansion.
SetSt [EBX+STM.Flags],stmtExpPrototype
XOR EAX,EAX
JMP .F50: ; If the field is macrooperation.
.F40:Invoke DictLookupIi::, EDI,ECX
JNC .F50: ; If the field is machine instruction.
; Field is an unknown identifier, assume it's label if not parsed yet. Otherwise assume operation.
.F45:JNSt [EBX+STM.Flags], stmtLabelParsed, .F60:
.F50:SetSt [EBX+STM.Flags],stmtOperationParsed
CMP EAX,PseudoPROGRAM::
JNE .F55:
SetSt [EBX+STM.Flags],stmtProgram
.F55:CALL .IncludeAny? ; INCLUDE* must be resolved in the first phase due to
JNE .F60: ; different %& expansion in included files suboperations.
SetSt [EBX+STM.Status],stmIncludeAny ; The operation is from INCLUDE* family.
.F60:SetSt [EBX+STM.Flags],stmtLabelParsed
.F70:CMP ESI,[EBX+STM.LineEnd] ; ESI is the end of previously parsed field.
JNB .S00:
LODSB ; ESI might point to the end of statement, in this case let's start the second pass.
CMP AL,10
JE .S00:
CMP AL,';'
JE .S00:
CMP AL,'\'
JNE .F90:
; Line continuation detected.
.F75:Invoke SrcFetchLine::,[EBX+STM.LineEnd],[EBX+STM.ChunkPtr]
JNC .F80:
JSt [EBX+STM.CtxStatusAll],ctxNoEmit, .S00: ; Supress error message if no emit.
Msg '6850' ; Unexpected line continuation.
JMP .S00:
.F80:MOV [EBX+STM.LineEnd],EAX
JZ .F75: ; The continued line was a machine/markup comment, ignore it and fetch the next one.
MOV ECX,EAX
SUB ECX,ESI
BufferStore [EBX+STM.SrcBuffer],ESI,ECX
JMP .F30: ; Continue horizontal parsing.
.F90:CMP AL,','
JNE .F20:
BufferStoreByte [EBX+STM.ExpBuffer],',' ; Operand-separating commas must be copied to ExpBuffer.
JMP .F30:
.S00: ; The second pass of horizontal parsing will inspect expanded text from ExpBuffer.
SetSt [EBX+STM.Flags],stmt2ndPass
; Expansion of %variables might have shuffled STM fields detected in 1st parsing pass. Do it again.
RstSt [EBX+STM.Flags],stmtLabelParsed|stmtOperationParsed
BufferRetrieve [EBX+STM.ExpBuffer] ; %variables are expanded and continuation lines concatenated.
ADD ECX,ESI
MOV [%StmPaLineEnd],ECX
Invoke StmParsePcPseudo,EBX,ESI,ECX ; Detect special case Macroname %MACRO etc.
.S10:MOV EDI,ESI
Invoke StmParseField, EBX, ESI,[%StmPaLineEnd]
MOV ECX,EAX ; End of field.
MOV ESI,EAX
SUB ECX,EDI ; Field brutto size.
StripSpaces EDI,ECX
JSt [EBX+STM.Flags],stmtOperationParsed, .S65:
XOR EDX,EDX
TEST ECX
JZ .S80:
MOV DH,[EDI+ECX-1] ; Terminating character.
CMP ECX,2
JB .S15:
MOV DL,[EDI+ECX-2] ; Detection of potentional double terminating colon.
.S15:StripColons EDI,ECX
Invoke DictLookup::, DictPrefixes::,EDI,ECX
JNC .S35:
CMP DH,':'
JNE .S50:
JSt [EBX+STM.Flags],stmtLabelParsed, .S25:
CMP DL,':'
JNE .S20:
SetSt [EBX+STM.Status],stmLabelIsPublic
.S20:; Label EDI,ECX will be stored to STM. Its lifetime is limited until StmClean.
JSt [EBX+STM.Status],stmLabelPresent, .S25:
JNSt [EBX+STM.Flags],stmtLabelParsed, .S30:
.S25:LEA EDX,[%StmPaErrPar] ; Error E6812.
MOV [EDX+0],EDI
MOV [EDX+4],ECX
LEA EAX,[EBX+STM.LabelPtr]
JSt [EBX+STM.CtxStatusAll],ctxNoEmit, .S80: ; Supress error msg if no emit.
Msg '6812',EAX,EDX,PgmStatus=pgmLastPass ; Trying to define 2nd label "%2S" when label "%1S" was already defined.
JMP .S80:
.S30:MOV EAX,[EBX+STM.Flags]
SetSt EAX,stmtLabelParsed
MOV [%StmPaFlags],EAX
MOV [EBX+STM.Flags],EAX
MOV [EBX+STM.LabelPtr],EDI
MOV [EBX+STM.LabelSize],ECX
TEST ECX
JZ .S80:
SetSt [EBX+STM.Status], stmLabelPresent
MOV EDX,[EBX+STM.Program]
TEST EDX
JZ .S80:
JNSt [EDX+PGM.Pgmopt.Status],pgmoptExecutable,.S80:
MOV EAX,[EDX+PGM.CurrentSect]
TEST EAX
JNZ .S80:
Invoke SssGetSegm::, EDX, sssPurposeCODE
MOV [EDX+PGM.CurrentSect],EAX
MOV [EBX+STM.Section],EAX
JMP .S80:
.S35:; Prefix EDI,ECX,EAX will be stored to STM.
SetSt [EBX+STM.Status],stmPrefixPresent
SetSt [EBX+STM.Flags],stmtLabelParsed
MOV EDX,[EBX+STM.NrOfPrefixes]
CMP EDX,4
JB .S40:
JSt [EBX+STM.CtxStatusAll],ctxNoEmit, .S80: ; Supress error message if no emit.
Msg '6824' ; More than 4 prefixes are not allowed in one statement.
JAE .S80:
.S40:INCD [EBX+STM.NrOfPrefixes]
LEA EDX,[EDX+2*EDX]
LEA EDX,[EBX+STM.Prefix1Ptr+4*EDX]
MOV [EDX],EDI
MOV [EDX+4],ECX
MOV [EDX+8],EAX
; Check if some prefix of the same group was parsed before.
AND EAX,iiPfxGrpAny
LEA ECX,[EBX+STM.Prefix1Ptr]
.S45:SUB EDX,12 ; Scan previously stored prefixes backward.
CMP EDX,ECX
JB .S80:
JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.S45: ; Ignore error if not emitting.
TEST [EDX+8],EAX ; Prefix data.
Msg cc=NZ,PgmStatus=pgmLastPass,'2820' ; Illegal combination of prefixes.',0
JMP .S45:
.S50:; The field EDI,ECX is not a prefix and it is not terminated with colon.
; It might be a known operation, otherwise assume it's a label.
; Assume EDI,ECX is a pseudoinstruction.
MOV EDX,stmPseudoOperation + stmOperationPresent
MOVD [%StmPaFlags],stmtOperationParsed
Invoke DictLookup::, DictPseudo::, EDI,ECX
JC .S55:
CALL .IncludeAny?
JNE .S60: ; If the pseudoinstruction is not INCLUDE*.
SetSt EDX,stmIncludeAny
JMP .S60:
.S55:; Go to .S30: when it is a label, although it might look like machine instruction or a macro.
JSt [EBX+STM.Status],stmPseudoBlock,.S30:
; Otherwise assume it is a macro.
MOV EDX,stmMacroOperation + stmOperationPresent
Invoke MacFind::, EDI,ECX
JNC .S60:
; Assume it's a machine instruction.
MOV EDX,stmIntelOperation + stmOperationPresent
Invoke DictLookupIi::, EDI,ECX
JNC .S60:
JNSt [EBX+STM.Flags],stmtLabelParsed,.S30: ; If label not encounterred yet, assume it's a label.
; Otherwise assume it's an unknown macro. Later this will report error on execution.
MOV EDX,stmOperationPresent
SUB EAX,EAX
.S60:; Field EDI,ECX is an operation. EAX=data, EDX=Stm.Status, [%StmPaFlags]=Stm.Flags.
MOV [EBX+STM.OperationPtr],EDI
MOV [EBX+STM.OperationSize],ECX
MOV [EBX+STM.OperationData],EAX
SetSt [EBX+STM.Status],EDX
MOV EAX,[%StmPaFlags]
SetSt [EBX+STM.Flags],EAX
JMP .S80:
StmParse.IncludeAny? PROC1 ; Input: EAX is operation data returned from DictLookup.
; Output: Returns ZF=1 if EAX is PseudoINCLUDE*
CMP EAX,PseudoINCLUDE::
JE .IA9:
CMP EAX,PseudoINCLUDE1::
JE .IA9:
CMP EAX,PseudoINCLUDEHEAD::
JE .IA9:
CMP EAX,PseudoINCLUDEHEAD1::
JE .IA9:
CMP EAX,PseudoINCLUDEBIN::
.IA9:RET
ENDP1 StmParse.IncludeAny?
.S65:; The field EDI,ECX is operand.
; The operand is a key when it starts with identifier immediately followed by equal sign.
LEA EDX,[EDI+ECX]
Invoke ExpParseIdentifier::, EDI,EDX,expFullstop
JC .S70: ; If potentional name size is zero.
PUSH EDI
ADD EDI,EAX
CMP EDI,[%StmPaLineEnd]
POP EDI
JNB .S70:
CMPB [EDI+EAX],'='
JNE .S70:
LEA ECX,[%StmPaOperand] ; Keyword operand.
MOV [ECX],EDI
MOV [ECX+4],EAX
LEA EAX,[EDI+EAX+1]
SUB EDX,EAX
StripSpaces EAX,EDX
MOV [ECX+8],EAX
MOV [ECX+12],EDX
BufferStore [EBX+STM.KeyBuffer],ECX,16
INCD [EBX+STM.NrOfKeys]
JMP .S80:
.S70:; The operand EDI,ECX is ordinal. It will be stored even when it is empty (ECX=0).
LEA EDX,[%StmPaOperand]
MOV [EDX+0],EDI
MOV [EDX+4],ECX
BufferStore [EBX+STM.OrdBuffer],EDX,8
.S75:INCD [EBX+STM.NrOfOrdinals]
.S80:CMP ESI,[%StmPaLineEnd] ; ESI points at the end of field, perhaps a comma.
JNB .S85:
CMPB [ESI],10
JE .S85:
CMPB [ESI],';'
JE .S85:
CMPB [ESI],','
JNE .S10:
INC ESI
JMP .S10: ; The next operand follows.
.S85:; Whole statement is parsed now. Some ordinals may be empty, trim them backward.
MOV EDX,[EBX+STM.NrOfOrdinals]
.S90:TEST EDX
JZ .S95:
BufferRetrieve [EBX+STM.OrdBuffer]
CMPD [ESI+8*EDX-8+4],0
JNZ .S95: ; If the last ordinal is not empty.
BufferDecrement [EBX+STM.OrdBuffer],Size=8
DEC EDX
JMP .S90:
.S95:MOV [EBX+STM.NrOfOrdinals],EDX
RstSt [EBX+STM.Flags],stmt2ndPass
.99:EndProcedure StmParse
%TxtEnd.Stm.Flags:stmt2ndPass is not set.If operand field is not expected (Stm.Flags:stmtOperationParsed is not set yet),
then it also can be terminated with
StmParseField Procedure Stm, TxtPtr, TxtEnd
MOV EAX,[%Stm]
MOV ESI,[%TxtPtr]
MOV EDX,[%TxtEnd]
MOV EBX,[EAX+STM.Flags]
RstSt [EAX+STM.Flags],stmtExpPrototype
SUB ECX,ECX ; Square brackets [] nesting level.
SUB EDI,EDI ; Curly brackets {} nesting level.
AND EBX,stmtOperationParsed+stmtExpPrototype
.00:CMP ESI,EDX ; Whitespaces at the beginning.
JNB .90:
LODSB
ExpClassify AL
TEST AH,expWhiteSpace
JNZ .00:
CMP AL,'\' ; At the nonwhite beginning of field.
JNE .20:
PUSH EAX
MOV EAX,[%Stm]
TESTD [EAX+STM.Flags],stmt2ndPass
POP EAX
JZ .80: ; Line-continuation detected.
; In 2nd StmParse pass the backslash is treated as an ordinary character.
JMP .65:
.10:CMP ESI,EDX ; Not at beginning.
JNB .90:
LODSB
.20:CMP AL,'"'
JE .25:
CMP AL,"'"
JNE .40:
.25:MOV AH,AL
.30:CMP ESI,EDX ; Inside quoted string.
JNB .90:
LODSB
CMP AL,AH
JNE .30:
JMP .10:
.40:CMP AL,'['
JNE .45:
INC ECX
JMP .10:
.45:CMP AL,']'
JNE .50:
DEC ECX
JMP .10:
.50:CMP AL,'{'
JNE .55:
INC EDI
JMP .10:
.55:CMP AL,'}'
JNE .60:
DEC EDI
JMP .10:
.60:CMP AL,10
JE .90:
CMP AL,';'
JE .80:
CMP AL,','
JE .80:
.65:PUSH EAX
XOR EAX,EAX
JSt EBX,stmtExpPrototype,.67:
MOV EAX,EBX ; stmtOperationParsed or 0.
.67: OR EAX,ECX
OR EAX,EDI
POP EAX
JNZ .10:
ExpClassify AL ; Not in braces and operation field not parsed yet.
TEST AH,expWhiteSpace ; Colon or space terminates the field.
JNZ .80:
CMP AL,':'
JNE .10:
.70:CMP ESI,EDX
JNB .90:
LODSB
CMP AL,':'
JE .70:
.80:DEC ESI
.90:MOV [%ReturnEAX],ESI
EndProcedure StmParseField
Stm.Status:stmPseudoBlock
if the statement looks like identifier %block, where %block is one
DictPcPseudo operations. This helps the statement-parser
to distinguish whether identifier is operation or label field in statements like
MyNewMacroinstruction %MACRO Operands is met for the 2nd time.
StmParsePcPseudo Procedure Stm, TxtPtr, TxtEnd
MOV EBX,[%Stm]
MOV ESI,[%TxtPtr]
MOV EDX,[%TxtEnd]
.10:CMP ESI,EDX
JNB .90:
LODSB
ExpClassify AL
TEST AH,expWhiteSpace
JNZ .10: ; Skip leading spaces.
DEC ESI
.20:CMP ESI,EDX
JNB .90:
LODSB
ExpClassify AL
TEST AH,expWhiteSpace
JZ .20: ; Skip the first field.
.30:CMP ESI,EDX
JNB .90:
LODSB
ExpClassify AL
TEST AH,expWhiteSpace
JNZ .30: ; Skip spaces between fields.
LEA EDI,[ESI-1] ; Ptr to potential %PSEUDOOPERATION.
.40:CMP ESI,EDX
JNB .50:
LODSB
ExpClassify AL
TEST AH,expWhiteSpace|expEol
JZ .40:
DEC ESI
.50:SUB ESI,EDI
Invoke DictLookup::, DictPcPseudo::,EDI,ESI
JC .90:
SetSt [EBX+STM.Status],stmPseudoBlock
.90:EndProcedure StmParsePcPseudo
%SET/A/B/C/E/2/S/L.
%SET*
and sets Stm.Flags:stmtSETany in this case.
%SETS or %SETL,
Stm.Flags:stmtSETLorS is set, too.
StmParseSET Procedure Stm, LabelPtr
MOV EBX,[%Stm]
MOV ESI,[%LabelPtr]
MOV EDX,[EBX+STM.LineEnd]
CMPB [ESI],'%%'
JNE .90:
Invoke VarParseName::,ESI,EDX
JC .10:
CMP EAX,varTypeLabel
JNE .10:
; The statement starts with formal label %: in label field. If this happened in macro-definition context,
; CTX.Status:ctxMacLabeled will be set to indicate that label of macro-invocation should not be declared
; right below the macro prototype, but it should expand only when %: occurs in some statement.
Invoke CtxFind::, ctxMACRO,EBX
JC .10:
JNSt [EAX+CTX.Status],ctxDefinition, .10:
SetSt [EAX+CTX.Status],ctxMacLabeled
; ESI is now behind potentional %variable name.
.10: CMP ESI,EDX
JNB .90:
LODSB
ExpClassify AL
TEST AH,expWhiteSpace
JNZ .10:
CMP AL,':'
JE .10:
; ESI is behind the start of 2nd field.
CMP AL,'%%'
JNE .90:
LEA EDI,[ESI-1] ; Start of potential %SET*.
.30: CMP ESI,EDX
JNB .40:
LODSB
ExpClassify AL
TEST AH,expLetter|expDigit
JNZ .30:
.35: DEC ESI
.40: MOV ECX,ESI
SUB ECX,EDI
Invoke DictLookup::, DictPseudoSET::, EDI,ECX
JC .90:
SetSt [EBX+STM.Flags],stmtSETany
; If the just found operation is %SETL or %SETS,
; a %variable name must follow as the one and only operand.
; The whole statement is not expanded at all.
CMP EAX,PseudopcSETS::
JE .50:
CMP EAX,PseudopcSETL::
JNE .90:
.50: SetSt [EBX+STM.Flags],stmtSETLorS
.90:EndProcedure StmParseSET
StmCheckFields Procedure Stm, Pattern
MOV EBX,[%Stm]
MOV EDX,[%Pattern] ; DL=label pattern.
.CheckLabel:
CMP DL,'?'
JE .CheckPrefix:
CMP DL,'*'
JE .CheckPrefix:
CMP DL,'0'
JNE .L1:
MOV ECX,'6810' ; Label is not expected in this statement.
JSt [EBX+STM.Status],stmLabelPresent, .ErrorECX:
JMPS .CheckPrefix:
.L1: MOV ECX,'6811' ; This statement requires a label.
JNSt [EBX+STM.Status],stmLabelPresent, .ErrorECX:
.CheckPrefix:
ROR EDX,8
CMP DL,'*'
JE .CheckOrdinals:
CMP DL,'0'
JNE .CheckOrdinals:
MOV ECX,'6820' ; Instruction prefix is not expected in this statement.
JSt [EBX+STM.Status],stmPrefixPresent, .ErrorECX:
.CheckOrdinals:
ROR EDX,8
CMP DL,'*'
JE .CheckKeywords:
MOV ESI,[EBX+STM.NrOfOrdinals]
CMP DL,'?' ; Zero or one ordinal required.
JNE .OP:
MOV ECX,'6831' ; This statement requires just one operand.
CMP ESI,1
JA .ErrorECX:
JMPS .CheckKeywords:
.OP: CMP DL,'+'
JNE .O0:
MOV ECX,'6839' ; Operand(s) missing.
CMP ESI,1
JB .ErrorECX:
JMPS .CheckKeywords:
.O0: ; DL is '0','1','2','3'
MOV EDI,EDX
AND EDI,0xF
MOV EAX,EDI
SHL EDI,24
LEA ECX,['6830'+EDI] ; Ordinal operands are not expected in this statement.
CMP EAX,ESI
JNE .ErrorECX:
.CheckKeywords:
ROR EDX,8
CMP DL,'0'
CLC
JNE .90:
CMPD [EBX+STM.NrOfKeys],0
JE .90:
MOV ECX,'6840'; Keyword operands are not expected in this statement.
.ErrorECX: Msg ECX,PgmStatus=pgmLastPass
STC
.90:EndProcedure StmCheckFields
[.data] StmListingSectionChanged:DB "::::Section changed.",13,10 StmListingAutoAlignment: DB "....AutoAlignment stuff.",13,10 StmListingDumpingAll: DB "----Dumping all.",13,10 StmListingLiteral1: DB "====ListLiterals in section [" StmListingLiteral2: DB "].",13,10 [.text]
StmListing Procedure Stm
EaoptStatus LocalVar ; Local copy of Ea.Eaopt.Status.
SssStatus LocalVar ; Local copy of current Stm.section Sss.Status.
SssPurpose LocalVar ; Local copy of current Stm.section Sss.Purpose.
Room4Value LocalVar ; Reserved for EQU value. 5,9,17 if section is 16,32,64bits.
DumpWidth LocalVar ; Local copy of Ea.Eaopt.DumpWidth.
DumpHexa LocalVar ; Two bytes of hexadecimal code to be streamed into dump column.
DumpPos LocalVar ; Position in in the dump column (1..DumpWidth-1). Incremented on dump of each character.
DumpPtr LocalVar ; Pointer to emitted bytes inside Stm.EmitBuffer. Incremented on each byte dump.
DumpBytes LocalVar ; Number of bytes emitted in the statement. Decremented on each byte dump.
Org LocalVar ; Actual origin, initizalized from Stm.Section.Org. Continuously updated on each listing line.
RelocPtr LocalVar ; Ptr to the currently processed RELOC record in Stm.RelocBuffer.
RelocEnd LocalVar ; Ptr to the end of records in Stm.RelocBuffer.
RelocOrg LocalVar ; Value of Org where decorator ( or ) should be inserted between dump hexa bytes.
Decorators LocalVar ; Contains ( or ) in LSB.
Disp8Char LocalVar ; Contains 2 .. 6 in LSB.
SrcLines LocalVar ; Number of physical source lines in STM.SrcBuffer.
SrcPtr LocalVar ; Start of current source line in STM.SrcBuffer.
SrcEnd LocalVar ; End of the last source line in STM.SrcBuffer.
LEA EDX,[Ea.Eaopt::]
MOV EBX,[%Stm]
MOV ECX,[EDX+EAOPT.Status]
MOV EAX,[EDX+EAOPT.DumpWidth]
JSt [EBX+STM.CtxStatusAll],ctxMacExpList,.03:
JSt [Src.Lst.Status::],lstListOn,.03: ; lstListOn is set in envelope and when EUROASM LIST= changes.
JNSt ECX,eaoptLIST, .98: ; No listing at all.
.03:MOV [%DumpWidth],EAX
MOV EDX,[EBX+STM.ChunkPtr]
XOR EAX,EAX
TEST EDX
JZ .08:
MOV EAX,[EDX+CHUNK.Status]
.08:MOV [%EaoptStatus],ECX
MOVB [Src.Lst.Status::],'|' ; Default Dump-Source column separator.
JSt [Src.Lst.Status::],lstNoList,.95: ; This statement is not listed (repeated %ENDWHILE etc).
JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.10: ; Do not list expanded source if ctxNoEmit.
JSt ECX,eaoptLISTVAR,.12:
.10:SetSt [Src.Lst.Status::],lstNothingExp ; Behave like the Stm had no expanded %variables.
.12:JNSt EAX,chunkIncluded,.13:
JSt [EBX+STM.CtxStatusAll],ctxMacExpList,.13:; List expansion even when LISTINCLUDE=OFF.
JNSt ECX,eaoptLISTINCLUDE,.95: ; Do not list included statements when LISTINCLUDE=OFF.
.13:JSt EAX,chunkBin|chunkOrigBin,.18:
JSt EAX,chunkResolved,.17:
JNSt EAX,chunkOrig,.18:
JNSt ECX,eaoptLISTINCLUDE,.18:
.17:MOVB [Src.Lst.Status::],'*' ; chunkOrig and chunkResolved are listed with separator '*'.
.18:JNSt [Src.Lst.Status::],lstEnvelope,.20:
MOVB [Src.Lst.Status::],' ' ; Both envelope statements are listed with separator ' '.
.20:
JNSt [EBX+STM.CtxStatusAll],ctxMACRO,.22: ; In ctxMACRO+ctxExpansion separate columns with '+'.
JNSt [EBX+STM.CtxStatusAll],ctxExpansion,.22:
JSt ECX,eaoptLISTVAR,.21: ; Inside macro expansion context, or at %ENDMACRO.
SetSt [Src.Lst.Status::],lstNothingExp ; Behave like the Stm had no expanded %variables.
.21:JNSt ECX,eaoptLISTMACRO,.95: ; Do not list %MACRO at start of expansion if LISTMACRO=OFF.
.22:SUB EAX,EAX
.23:Invoke CtxPeek::,ctxMACRO,EAX
JC .25: ; If not in macro.
JNSt [EAX+CTX.Status],ctxExpansion, .23:
JSt [EAX+CTX.Status],ctxPrototype, .23: ; Macro invocation is not behind '+'.
MOVB [Src.Lst.Status::],'+' ; Separator in macro expansion context.
JNSt ECX,eaoptLISTMACRO,.95:
.25:Invoke CtxPeek::,ctxRepeat,0
JC .27:
; Stm is in %FOR,%REPAT,%WHILE context. Display only the 1st expansion.
JSt [EAX+CTX.Status],ctx1stRepeat,.27: ; Display 1st expansion regardless of LISTREPEAT.
MOVB [Src.Lst.Status::],'+'
JNSt ECX,eaoptLISTREPEAT,.95:
.27: ; Start of listing formating. EBX=Stm, EDI=Lst, EDX=Ea.Eaopt ECX=Ea.Eaopt.Status
JNSt [Src.Lst.Status::],lstAsRepeated,.28:
MOVB [Src.Lst.Status::],'+'
.28:JSt ECX,eaoptDUMP,.34:
; Dump column supressed. List only source, expanded source and error messages.
BufferRetrieve [EBX+STM.SrcBuffer]
; Split source statement ESI,ECX to physical lines, prefixed with || or |+.
MOV EDI,ESI
.29:JECXZ .30:
MOV ESI,EDI
MOV AL,10 ; LineFeed.
REPNE SCASB
MOV EDX,EDI
SUB EDX,ESI
StreamStoreByte [Src.Lst.Stream::],'|'
MOV AL,[Src.Lst.Status::] ; '|' or '+'
StreamStoreByte [Src.Lst.Stream::],AL
XCHG EDX,ECX
CALL .StreamTrim:
XCHG ECX,EDX
JMP .29:
.30:JSt [Src.Lst.Status::],lstNothingExp,.32:
JNSt [%EaoptStatus],eaoptLISTVAR,.32:
BufferRetrieve [EBX+STM.ExpBuffer]
StreamStoreWord [Src.Lst.Stream::],'|!'
; Expanded src is always one physical line, store it as a machine comment.
CALL .StreamTrim:
.32:BufferRetrieve [EBX+STM.MsgBuffer] ; Errors and warning are already prefixed with machine comment mark '|#'.
JECXZ .33:
CALL .StreamTrim:
.33:JMP .98:
.34: ; Start streaming complete listing (dump and source columns).
BufferRetrieve [EBX+STM.EmitBuffer]
; Initialization of dumped bytes.
MOV [%DumpPtr],ESI
MOV [%DumpBytes],ECX
; Initialization of source lines.
MOVD [%SrcLines],0
BufferRetrieve [EBX+STM.SrcBuffer]
MOV EDI,ESI ; Count physical lines in source text of the statement [%SrcLines].
MOV [%SrcPtr],ESI
MOV [%SrcEnd],ESI
ADD [%SrcEnd],ECX
MOV AL,10 ; End of physical line.
.35: JECXZ .36:
REPNE SCASB
INCD [%SrcLines]
JMP .35:
.36: LEA EDI,[Src.Lst::]
SUB ECX,ECX
JSt [Src.Lst.Status::],lstNoData|lstTRUE|lstFALSE,.40:
JNSt [Src.Lst.Status::],lstSet,.52:
JNSt [Src.Lst.Status::],lstEQU,.39:
; Stm is EQU. SetBuffer in this case already contains symbol value
; (prepared in PseudoEQU),
; but symbol section temporarily stored in Lst.Section must be dumped first.
BufferRetrieve [Src.Lst.SetBuffer::]
MOV [%DumpPtr],ESI ; Symbol binary value.
MOV [%DumpBytes],ECX ; 2,4,8.
SAL ECX,1
INC ECX
MOV [%Room4Value],ECX ; 5,9,17.
MOV ECX,[Src.Lst.Section::] ; (Temporary) symbol section.
CALL .StoreSection: ; [SymbolSection]
StreamStoreByte [Src.Lst.Stream::],':'
INCD [%DumpPos]
.37: CMPD [%DumpBytes],0
JNG .38:
MOV ESI,[%DumpPtr]
LODSB
MOV [%DumpPtr],ESI
CALL .StoreHexa:
DECD [%DumpBytes]
JMP .37:
.38: CALL .StuffDumpEnd:
BufferClear [Src.Lst.SetBuffer::]
MOV EAX,[Src.Lst.Status::]
StreamStoreByte [Src.Lst.Stream::],AL ; Usually '|'.
CALL .StoreSrcLine:
CMPD [%SrcLines],0
JZ .95: ; If no more source lines.
StreamStoreByte [Src.Lst.Stream::],'|'
MOVD [%DumpPos],2
JMP .38:
.39: ; Stm is %SET, %IF, %ELSE, %ENDREPEAT, %WHILE.
; Hexadecimal %SET data or boolean result will be displayed in dump column.
BufferRetrieve [Src.Lst.SetBuffer::]
MOV [%DumpPtr],ESI
.40: MOV [%DumpBytes],ECX
.42: ; Keep storing both %var-dump and source columns while there are source lines.
MOV ECX,[%SrcLines]
JECXZ .43:
CALL .StoreSetLine:
MOV AL,[Src.Lst.Status::]
StreamStoreByte [Src.Lst.Stream::],AL ; Usually '|', in expansion '+'.
CALL .StoreSrcLine:
JMP .42:
.43: JSt [Src.Lst.Status::],lstNothingExp,.47:
CALL .StoreSetLine: ; Expanded source line is due.
StreamStoreByte [Src.Lst.Stream::],'!' ; Expanded line is treated as machine comment.
BufferRetrieve [EBX+STM.ExpBuffer]
CALL .StreamTrim:
.47:; Store the remaining %var-dump bytes if DUMPALL.
JNSt [%EaoptStatus],eaoptDUMPALL,.50:
.48: MOV ECX,[%DumpBytes]
JECXZ .50:
CALL .StoreSetLine:
StreamStore [Src.Lst.Stream::],StmListingDumpingAll,SIZE#StmListingDumpingAll
JMP .48:
.50: BufferClear [Src.Lst.SetBuffer::]
JMP .95:
.52:; Initialization of origin.
XOR EAX,EAX
MOV [%SssStatus],EAX
MOV [%SssPurpose],EAX
MOV [%Org],EAX
JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.80:
; Inserted section-change line.
JNSt [Src.Lst.Status::],lstSectKeep,.54: ; Suppress [sect] change in dump column.
MOV EAX,[EBX+STM.Program]
TEST EAX
JZ .54:
MOV ECX,[EAX+PGM.CurrentSect] ; ENDSTRUC should have Org from [Struc] SSS in listing.
JMPS .56:
.54:MOV ECX,[EBX+STM.Section]
.56:TEST ECX
JZ .62:
MOV EAX,[ECX+SSS.Status]
MOV [%SssStatus],EAX
MOV EAX,[ECX+SSS.Purpose]
MOV [%SssPurpose],EAX
MOV EAX,[ECX+SSS.OrgLow]
MOV [%Org],EAX
CMP ECX,[Src.Lst.Section::]
JE .62:
; Section ECX has changed - store line with current section name |[section] ::::AutoSegment changed.
; or, if lstSectInline, |[MyStruc] |MyStruc STRUC
MOV [Src.Lst.Section::],ECX
MOVD [%Room4Value],0
RstSt [Src.Lst.Status::],lstTilde
CALL .StoreSection: ; |[section]
CALL .StuffDumpEnd:
JNSt [Src.Lst.Status::],lstSectInline,.58:
StreamStoreByte [Src.Lst.Stream::],'|'
CALL .StoreSrcLine:
JMP .62:
.58:JNSt [Src.Lst.Status::],lstLiteral,.60:
StreamStore [Src.Lst.Stream::],StmListingLiteral1,SIZE#StmListingLiteral1 ;====Listing literal section [
MOV ECX,[Src.Lst.Section::]
JECXZ .59:
StreamStore [Src.Lst.Stream::],[ECX+0],[ECX+4]
.59:StreamStore [Src.Lst.Stream::],StmListingLiteral2,SIZE#StmListingLiteral2 ; ].
JMP .62:
.60:StreamStore [Src.Lst.Stream::],StmListingSectionChanged,SIZE#StmListingSectionChanged ;...AutoSegment changed.
.62: ; Inserted autoalignment line.
MOV ECX,[EBX+STM.AlignBytes]
TEST ECX
JZ .72:
JNSt [Src.Lst.Status::],lstEQU,.63:
ADD [%Org],ECX
JMP .72:
; Store line with ECX alignment bytes. |000000 ;
.63:PUSH ECX
CALL .StoreOrg:
POP ECX
ADD [%Org],ECX
RstSt [Src.Lst.Status::],lstTilde ; DUMPALL is ignored when dumping autoalignment.
Invoke EaBufferReserve::,StmListing
Invoke SssEmitAlignment::,[Src.Lst.Section::],ECX,EAX
BufferRetrieve EAX
Invoke EaBufferRelease::,EAX ; ESI,ECX still contains the alignment stuff.
.64: XOR EAX,EAX
LODSB
LEA EDI,[%DumpHexa]
StoH EDI,Size=2
MOV DX,[EDI-2]
JSt [%SssPurpose],sssPurposeCODE,.65:
MOV DX,'00'
JNSt [%SssPurpose],sssPurposeBSS,.65:
MOV DX,'..'
.65:MOV EAX,[%DumpPos]
ADD EAX,2
CMP EAX,[%DumpWidth]
JA .68:
INC EAX
CMP EAX,[%DumpWidth]
JBE .66:
CMP ECX,1
JA .68:
.66:StreamStoreWord [Src.Lst.Stream::],DX ; Store alignment stuff.
ADDD [%DumpPos],2
LOOP .64:
JMPS .70:
.68:SetSt [Src.Lst.Status::],lstTilde
.70:CALL .StuffDumpEnd:
StreamStore [Src.Lst.Stream::],StmListingAutoAlignment,SIZE#StmListingAutoAlignment
.72: ; Initialize relocations.
SUB EAX,EAX
MOV [%Decorators],EAX
DEC EAX
MOV [%RelocOrg],EAX
BufferRetrieve [EBX+STM.RelocBuffer]
MOV [%RelocPtr],ESI
MOV [%RelocEnd],ESI
TEST ECX
JZ .80: ; If there are no relocations in this statement.
ADD [%RelocEnd],ECX
.74: CMP ESI,[%RelocEnd]
JNB .80: ; If no more valid relocations.
MOV EAX,[ESI+RELOC.OrgLow]
; If not listing literals, the offset of relocation is relative to the beginning of statement,
; because the statement was not flushed to section yet.
; If literal, it is relative to segment, because PgmListLiterals is invoked after SssLinkSection.
JSt [Src.Lst.Status::],lstLiteral,.76:
ADD EAX,[%Org]
.76: ; RELOC records between [%RelocPtr] and [%RelocEnd] may not all be relevant
; to the emitted data starting at [%Org]. Skip them to avoid superfluous '()' in dump.
CMP EAX,[%Org]
JAE .78: ; If it's relevant to this statement.
ADD ESI,SIZE#RELOC ; ESI pointed to lower relocation, skip it.
MOV [%RelocPtr],ESI
JMP .74: ; Try the next relocation.
.78: MOV [%RelocOrg],EAX ; Offset of fixup withing current segment. Will be marked with '(' or '['.
CALL .GetDecorators ; Returns EAX='[]' for the 1st relocation in statement.
MOV [%Decorators],EAX
.80: ; Keep storing both dump and source columns while there are source lines.
MOV ECX,[%SrcLines]
JECXZ .84:
CALL .StoreOrg:
CALL .StoreDumpLine:
JSt [Src.Lst.Status::],lstLiteral,.82: ; |source will be replaced with =Literal.
MOV AL,[Src.Lst.Status::]
StreamStoreByte [Src.Lst.Stream::],AL ; Usually '|'.
.82: CALL .StoreSrcLine:
JMP .80:
.84: ; Out of source lines. Now list expanded source line and the rest of dump bytes.
JSt [Src.Lst.Status::],lstNothingExp,.90: ; If there were no %variables in source line or LISTVAR=NO.
; Expanded source line is due.
CMPD [%DumpBytes],0
JA .86:
RstSt [Src.Lst.Status::],lstTilde
StreamStoreByte [Src.Lst.Stream::],'|'
MOVD [%DumpPos],2
CALL .StuffDumpEnd:
JMPS .88:
.86: CALL .StoreOrg:
CALL .StoreDumpLine:
.88: StreamStoreByte [Src.Lst.Stream::],'!' ; Whole expanded source line is treated as a machine comment.
BufferRetrieve [EBX+STM.ExpBuffer]
CALL .StreamTrim:
.90: ; Store the remaining dump bytes if DUMPALL=YES and if not in BSS or STACK segment.
JNSt [%SssPurpose],sssPurposeDATA|sssPurposeRODATA|sssPurposeCODE,.95:
JNSt [%EaoptStatus],eaoptDUMPALL,.95:
.92: MOV ECX,[%DumpBytes]
JECXZ .95:
CALL .StoreOrg:
CALL .StoreDumpLine:
StreamStore [Src.Lst.Stream::],StmListingDumpingAll,SIZE#StmListingDumpingAll
JMP .92:
.95: ; Store messages, if any.
BufferRetrieve [EBX+STM.MsgBuffer]
JECXZ .98:
StreamStore [Src.Lst.Stream::],ESI,ECX
.98: BufferClear [EBX+STM.MsgBuffer]
; Here follow all StmListing.subprocedures.
; Input: EBX=^Stm, EDI=^Lst, EBP=stack frame.
StmListing.StreamTrim: PROC1 ; Right-trim ESI,ECX, save to stream and terminate with CR+LF. EAX,ECX is changed.
.T1:JECXZ .T6:
DEC ECX
CMPB [ESI+ECX],32
JBE .T1:
INC ECX
MOV AL,'|'
CMP [Src.Lst.Status],AL
JE .T5:
; When dump separator is not '|', every '|' in source ESI,ECX will be replaced with '!'.
PUSH ECX,EDI
MOV EDI,ESI
.T2: REPNE SCASB
JNE .T4:
MOVB [EDI-1],'!'
JMP .T2:
.T4:POP EDI,ECX
.T5:StreamStore [Src.Lst.Stream::],ESI,ECX ; Source line with white-spaces rtrimmed off.
.T6:StreamStore [Src.Lst.Stream::],=W(0x0A0D),2 ; CR+LF.
RET
ENDP1 StmListing.StreamTrim:
StmListing.StoreSection: PROC1 ; ECX=^SSS. Store |[Shortened~~sectionName], leave room for [%Room4Value] characters.
MOV AX,'|['
StreamStoreWord [Src.Lst.Stream::],AX
MOVD [%DumpPos],3
TEST ECX
JZ .R7: ; If empty section.
MOV EAX,[%DumpWidth]
SUB EAX,4
SUB EAX,[%Room4Value]
JLE .R7:
MOV ESI,[ECX+SSS.NamePtr]
MOV ECX,[ECX+SSS.NameSize]
CMP EAX,ECX
JAE .R6: ; Jump if the whole section name fits to dump width.
LEA EDX,[ESI+ECX]
SHR EAX,1 ; Long section name will be from-the middle-shortened.
ADD [%DumpPos],EAX
StreamStore [Src.Lst.Stream::],ESI,EAX
StreamStoreWord [Src.Lst.Stream::],'~~'
ADDD [%DumpPos],2
MOV ECX,[%DumpWidth]
SUB ECX,[%DumpPos]
SUB ECX,[%Room4Value]
DEC ECX
MOV ESI,EDX
SUB ESI,ECX
.R6:StreamStore [Src.Lst.Stream::],ESI,ECX
ADD [%DumpPos],ECX
.R7:StreamStoreByte [Src.Lst.Stream::],']'
INCD [%DumpPos]
RET
ENDP1 StmListing.StoreSection:
StmListing.StoreOrg: PROC1 ; Store '|' (left dump column separator) followed by hexa offset [%Org] and ':', initialize [%DumpPos].
MOVD [%DumpPos],2
StreamStoreByte [Src.Lst.Stream::],'|'
JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.O9:
INCD [%DumpPos]
MOV EAX,[%Org]
MOV ECX,4 ; Width of dumped address is 16 bits in 16bit segment, otherwise 32 bits.
JNSt [%SssStatus],sssWidth16,.O2:
MOV CL,2
SHL EAX,16
.O2:ROL EAX,8
CALL StmListing.StoreHexa:
LOOP .O2:
.O3:StreamStoreByte [Src.Lst.Stream::],':' ; Address:data separator.
.O9:RET
ENDP1 StmListing.StoreOrg:
StmListing.StoreHexa: PROC1 ; Store one hexa byte AL to listing stream. Advance [%DumpPos] by 2. Destroys EDX.
PUSH EAX
AND AL,0x0F
LEA EDX,[%DumpHexa]
ADD AL,0x90
DAA
ADC AL,0x40
DAA
MOV [EDX+1],AL
POP EAX
PUSH EAX
SHR EAX,4
AND AL,0x0F
ADD AL,0x90
DAA
ADC AL,0x40
DAA
MOV [EDX+0],AL
StreamStore [Src.Lst.Stream::],EDX,2
POP EAX
ADDD [%DumpPos],2
RET
ENDP1 StmListing.StoreHexa:
StmListing.NextReloc PROC1 ; Update %RelocOrg, %Decorators, RelocPtr.
; Input: - Output: EAX,ECX,ESI undefined.
; This subproc is called from .StoreDumpLine right after decorator from [%Decorators] has been listed
; (either opening or closing bracket), due to [%DumpOrg] has just reached [%RelocOrg].
; [%Decorators] contains in LSB current decorator char (bracket) and it will be byte-shifted for the next (closing) bracket.
; [%RelocOrg] will be increased by relocation width.
; If .NextReloc is called after the last closing bracket, it advances ESI to the next RELOC and prepares
; [%Decorators] and [%RelocOrg] for the next relocation, if some exists.
; Example of dump with relocations in 16bit addressing mode:
; 12(3456) relocRel Self-relative relocation. [%Decorators]='()'
; 12[3456] relocAbsVA Segm-relative relocation. [%Decorators]='[]'
; 12{3456} relocPara Paragraph addr.relocation. [%Decorators]='{}'
; 12[3456]{789A} relocFar Far pointer relocation. [%Decorators]='[]{}'
; 1234<5 relocDisp8N Disp8*32 decoration. [%Decorators]='<5' ; >>
MOV EAX,[%Decorators] ; Decorator in AL has just been listed.
MOV ESI,[%RelocPtr] ; ESI is now the current RELOC record.
MOV ECX,EAX
JECXZ .N1: ; If there's no decorator left, i.e. if the relocation ESI has just been completely decorated.
SHR EAX,8 ; Otherwise prepare the next decorator (usually a closing bracket) to LSB.
MOV [%Decorators],EAX
TEST AL ; No more markers?
JNZ .N5: ; If the decoration of relocation ESI is still pending.
.N1: ADD ESI,SIZE#RELOC ; All decorators from this relocation ESI are listed, prepare for the next RELOC.
DEC EAX ; Set RelocOrg to -1 when there are no more relocations in this statement.
CMP ESI,[%RelocEnd]
JNB .N2: ; If there are no more relocations in this statement.
MOV [%RelocPtr],ESI
; New relocation starts. ESI is the current RELOC to dump.
CALL StmListing.GetDecorators
MOV [%Decorators],EAX
MOV EAX,[ESI+RELOC.OrgLow] ; EAX=Unpatched origin, relative to stm data. If dumping literal, it's relative to the section data.
JSt [Src.Lst.Status::],lstLiteral,.N2:
ADD EAX,[EBX+STM.OffsetLow]
.N2: MOV [%RelocOrg],EAX
RET
.N5: JNSt [ESI+RELOC.Status],relocFar, .N7:
CMP AL,'{' ; Is it the segment part of far pointer decoration?
JE .N9: ; In that case leave [%RelocOrg] unchanged, so the decorator { will immediately follow ].
CMP AL,'}' ; Is it the end of segment part of far pointer decoration?
MOV ECX,2 ; If yes, the closing bracket '}' will follow after 2 dumped bytes of segment value.
JE .N8:
.N7: CALL StmListing.GetDecorators ; Otherwise find the distance of the next decorator.
.N8: ADD [%RelocOrg],ECX
.N9: RET
ENDP1 StmListing.NextReloc:
StmListing.GetDecorators: PROC1 ; Get the set of listing decorator characters and relocation size.
; Input: ESI=^RELOC.
; Output: EAX=The set of relocation decorators. The last one is in LSB (AL).
; ECX=next decorator distance in dumped bytes (0,1,2,4,8).
MOV EAX,[ESI+RELOC.Status]
MOV ECX,EAX
AND ECX,relocWidthMask
SHR ECX,19 ; Convert relocWidthMask to size 2,4,8.
JNZ .G5:
INC ECX
.G5: JSt EAX,relocAbsVA,.relocAbsVA:
JSt EAX,relocRel, .relocRel:
JSt EAX,relocPara, .relocPara:
JSt EAX,relocFar, .relocFar:
JSt EAX,relocDisp8N,.relocDisp8N:
.relocResolved:
XOR EAX,EAX
XOR ECX,ECX
RET
.relocDisp8N:
XOR ECX,ECX
AND EAX,relocDisp8N ; EAX=0x1000_0000..0x7000_0000.
SHR EAX,20
OR AH,'0'
MOV AL,'<' ; >
RET
.relocAbsVA:
MOV EAX,[ESI+RELOC.Status]
AND EAX,relocExtAttr
CMP EAX,dictAttrPARA<<16 ; >>
MOV EAX,'[]'
JE .relocPara:
RET
.relocRel:
MOV EAX,'()'
RET
.relocPara:
MOV CL,2 ; relocPara {1234}.
MOV EAX,'{}'
RET
.relocFar:
; MOV CL,2 ; relocWidth16 [1234]{5678}.
; JSt EAX,relocWidth16, .Far:
; MOV CL,4 ; relocWidth32 [12345678]{9ABC}.
;.Far:
MOV EAX,'[]{}'
RET
ENDP1 StmListing.GetDecorators:
StmListing.StuffDumpEnd: PROC1 ; Keep storing spaces or tildes until the end of dump column.
MOV DL,'~'
JSt [Src.Lst.Status::],lstTilde,.E2:
MOV DL,' '
.E2:MOV ECX,[%DumpPos]
.E3:CMP ECX,[%DumpWidth]
JAE .E9:
StreamStoreByte [Src.Lst.Stream::],DL
INC ECX
JMP .E3:
.E9:RET
ENDP1 StmListing.StuffDumpEnd:
StmListing.StoreSrcLine: PROC1 ; Store one source physical line to listing stream, advance [%SrcPtr], decrement [%SrcLines].
MOV ESI,[%SrcPtr]
MOV ECX,[%SrcEnd]
SUB ECX,ESI
JNA .80:
PUSH EDI
MOV EDI,ESI
MOV AL,10 ; LineFeed.
REPNE SCASB
MOV ECX,EDI
MOV [%SrcPtr],EDI
SUB ECX,ESI
POP EDI
CALL StmListing.StreamTrim:
.80: DECD [%SrcLines]
RET
ENDP1 StmListing.StoreSrcLine:
StmListing.StoreDumpLine: PROC1 ; Store one row of dump bytes and then empty stuff until DumpPos will reach DumpWidth.
; Column separator is expected to be stored to stream after .StoreDumpLine call.
RstSt [Src.Lst.Status::],lstTilde
JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.D9:
.D0: CMPD [%DumpBytes],0
JG .D2: ; If some bytes left unstored.
; All dumped. Reloc marker ( ) might have been left open.
MOV EAX,[%Decorators]
CMP AL,0
JE .D9:
CMP AL,'['
JE .D9:
CMP AL,'('
JE .D9:
CMP AL,'{'
JE .D9:
.D1: MOV EAX,[%DumpPos]
INC EAX
CMP EAX,[%DumpWidth] ; Is there room for closing decorator in this physical line?
JA .D9:
JMP .D3:
.D2: MOV EAX,[%DumpPos]
ADD EAX,2
CMP EAX,[%DumpWidth] ; Is there enough room for the hexabyte in this physical line?
JA .D7: ; If not, quit with the line.
CMPD [%DumpBytes],1
JE .D3:
CMPD [%SrcLines],1
JA .D3:
JSt [%EaoptStatus],eaoptDUMPALL,.D3:
; No more source lines but still may need to dump some data.
INC EAX
CMP EAX,[%DumpWidth]
JA .D8: ; Not all data can be dumped, mark that with lstTilde.
.D3: MOV EAX,[%Org]
CMP EAX,[%RelocOrg] ; Has dumped origin reached position of a relocable address?
JB .D4: ; Jump if not yet reached.
MOV EAX,[%Decorators] ; Relocation begining or end is due, insert one of ()[]{}.
TEST AL
JZ .DN:
StreamStoreByte [Src.Lst.Stream::],AL
INCD [%DumpPos]
.DN: CALL StmListing.NextReloc:
JMP .D0:
.D4: CMPD [%DumpBytes],0
JBE .D9:
MOV ESI,[%DumpPtr]
LODSB
MOV [%DumpPtr],ESI
JSt [%SssPurpose],sssPurposeInitMask, .D5:
StreamStoreWord [Src.Lst.Stream::],'..' ; In BSS segment store .. instead of hexa byte.
ADDD [%DumpPos],2
JMPS .D6:
.D5: CALL StmListing.StoreHexa:
.D6: INCD [%Org]
CMPD [%DumpBytes],0
JZ .D0:
DECD [%DumpBytes]
JMP .D0:
.D7: CMPD [%SrcLines],1
JA .D9: ; While unlisted source lines exist, continue dumping data.
; No more source lines are available. Repeated dump column will continue only if DUMPALL=ON, otherwise lstTilde.
JNSt [%SssPurpose],sssPurposeCODE|sssPurposeDATA|sssPurposeRODATA,.D8: ; Shorten dump with tilde in BSS section (regardless of DUMPALL).
JSt [%EaoptStatus],eaoptDUMPALL,.D9: ; Shorten dump with tilde when DUMPALL=OFF.
.D8: SetSt [Src.Lst.Status::],lstTilde
.D9: CALL StmListing.StuffDumpEnd:
RET
ENDP1 StmListing.StoreDumpLine:
StmListing.StoreSetLine: PROC1 ; Store one row of dump bytes, then store empty stuff until DumpPos will reach DumpWidth.
; Column separator is expected to be stored to stream after .StoreSetLine call.
RstSt [Src.Lst.Status::],lstTilde
StreamStoreByte [Src.Lst.Stream::],'|' ; Machine comment in the 1st dump column.
MOVD [%DumpPos],2
JSt [Src.Lst.Status::],lstTRUE|lstFALSE,.S0:
JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.S9:
.S0: JNSt [Src.Lst.Status::],lstTRUE,.S1: ; In boolean-type statements list TRUE or FALSE in dump column.
StreamStore$ [Src.Lst.Stream::],=B"TRUE"
ADDD [%DumpPos],4
JMPS .S2:
.S1: JNSt [Src.Lst.Status::],lstFALSE,.S2:
StreamStore$ [Src.Lst.Stream::],=B"FALSE"
ADDD [%DumpPos],5
.S2: RstSt [Src.Lst.Status::],lstTilde+lstTRUE+lstFALSE
CMPD [%DumpBytes],0
JNG .S9:
MOV EAX,[%DumpPos]
ADD EAX,2
CMP EAX,[%DumpWidth]
JA .S7:
CMPD [%DumpBytes],1
JE .S4: ; If no more emitted bytes to dump.
CMPD [%SrcLines],1
JA .S4: ; If no more source physical lines to list.
JSt [%EaoptStatus],eaoptDUMPALL,.S4:
INC EAX
CMP EAX,[%DumpWidth]
JA .S8:
.S4: MOV ESI,[%DumpPtr]
LODSB
MOV [%DumpPtr],ESI
.S6: CALL StmListing.StoreHexa:
DECD [%DumpBytes]
JMP .S2:
.S7: CMPD [%SrcLines],1
JA .S9:
JSt [%EaoptStatus],eaoptDUMPALL,.S9:
.S8: SetSt [Src.Lst.Status::],lstTilde
.S9: CALL StmListing.StuffDumpEnd: ; Fill the rest of dump column with spaces.
RET
ENDP1 StmListing.StoreSetLine:
.99:EndProcedure StmListing
Stm.RelocBuffer to
Stm.Section.RelocBuffer and patches their origin by Stm.Section.Org.
Stm.Section.
Stm.EmitBuffer to Stm.Section.EmitBuffer
and updates Sss.Org, Sss.Top.
StmFlush Procedure Stm
MOV EBX,[%Stm]
MOV EDX,[EBX+STM.Program]
MOV EDI,[EBX+STM.Section]
TEST EDX
JZ .90:
JSt [EBX+STM.Flags],stmtKeepSect,.10:
MOV [EDX+PGM.CurrentSect],EDI ; Update program, because section was changed in the statement EBX.
.10:RstSt [EBX+STM.Flags],stmtKeepSect
TEST EDI
JZ .90:
MOV EAX,[EBX+STM.EmitBuffer]
BufferRetrieve EAX
OR ECX,[EBX+STM.AlignBytes]
JZ .90: ; ECX=0 when there's nothing to align and|or emit.
MOV ESI,EAX ; Save the statement's emit buffer to ESI for later.
JSt [EDI+SSS.Purpose],sssPurposeCODE|sssPurposeDATA|sssPurposeRODATA,.20:
JNSt [EBX+STM.Flags],stmtNotBSS,.30:
.20:SetSt [EDI+SSS.Status],sssNotBSS ; Any emitting statement makes the section sssNotBSS.
.30:XOR ECX,ECX
JNSt [EDX+PGM.Status],pgmLastPass,.50:
MOV ECX,[EBX+STM.RelocBuffer] ; Emit relocations in the last pass only.
.50:Invoke SssEmit::,EDI,ESI,ECX,[EBX+STM.AlignBytes] ; Flush statemnent buffers to section EDI buffers.
.90:EndProcedure StmFlush
ALIGN=, ADDR=, BCST=, CODE=, DATA=,
DISP=, DIST=, EH=, IMM=, MASK=,
NESTINGCHECK=, OPER=, ROUND =, SAE=, SCALE=,
ZEROING=. It walks through all statement keyword operands
and warns if unexpected keyword appeared in the statement..MfgExplicit, .MfxExplicit and .Align.ALIGN= and NESTINGCHECK=
do not need to be explicitly allowed.
StmGetIiModifiers Procedure Stm, Ii
MOV EBX,[%Stm]
MOV EDI,[%Ii]
BufferRetrieve [EBX+STM.KeyBuffer]
LEA EDX,[ESI+ECX] ; End of keyword operands buffer contents.
SUB ESI,16
.20: ADD ESI,16 ; Next keyword operand (4 dwords).
CMP ESI,EDX
JNB .90: ; If no more keywords.
PUSH EDX
CALL .EvalKey:
POP EDX
JMP .20:
.EvalKey: PROC1 ; Handle keyword name and value.
; Input: ESI points to 4 Dwords with keyword operand NamePtr,NameSize,ValuePtr,ValueSize.
; EDI is pointer to II structure.
; Output: II structure modified. Preserves EBP,ESI,EDI.
LEA ECX,[ESI+8] ; Prepare ECX to point at the value (in case of error it will be Msg argument).
Invoke DictLookup::,DictIiMfs::,[ESI+0],[ESI+4] ; Special modifiers ALIGN=, NESTINGCHECK=.
JC .Mfg:
Dispatch EAX,iiMfsALIGN_Mask, iiMfgNESTING_OFF
RET
.Mfg: Invoke DictLookup::,DictIiMfg::,[ESI+0],[ESI+4] ; General modifiers DATA=, DIST= etc.
JC .Mfx:
JNSt [EDI+II.MfgAllowed],EAX,.W3741: ; Instruction modifier !1S= is not expected in this statement. Ignored.
Dispatch EAX,iiMfgCODE_Mask,iiMfgDATA_Mask,iiMfgDISP_Mask,iiMfgIMM_Mask,iiMfgDIST_Mask,iiMfgADDR_Mask,iiMfgSCALE_Mask
.Mfx: Invoke DictLookup::,DictIiMfx::,[ESI+0],[ESI+4] ; AVX modifiers PREFIX=, MASK= etc.
JC .W3740: ; Illegal instruction modifier !1S=. Ignored.
JNSt [EDI+II.MfxAllowed],EAX,.W3741: ; Instruction modifier !1S= is not expected in this statement. Ignored.
Dispatch EAX,iiMfxPREFIX_Mask,iiMfxMASK_Mask,iiMfxZEROING_Mask,iiMfxBCST_Mask,iiMfxEH_Mask,iiMfxSAE_Mask,iiMfxROUND_Mask,iiMfxOPER_Mask
RET
.W3740:Msg '3740',ESI ; Illegal instruction modifier !1S=. Ignored.
RET
.W3741:Msg '3741',ESI ; Instruction modifier !1S= is not expected in this statement. Ignored.
RET
.W3742:Msg '3742',ESI,ECX,EBX ; Illegal !1S= value "!2S". Expected !3L.
RET
.W3743:Msg '3743',ESI,ECX ; Value !1S=!2S is not acceptable in this statement. Ignored.
RET
.W3744:Msg '3744',ESI,ECX,EAX ; Value !1S=!2S=!3D is not acceptable, 0..7 expected.
RET
.iiMfgNESTING_OFF: ; Accept NESTINGCHECK=OFF/ON or other Boolean value. Store to II.MfgExplicit.
RstSt [EDI+II.MfgExplicit],iiMfgNESTING_OFF ; Leave NESTINGCHECK=ON by default.
Invoke ExpEvalBoolean::,[ESI+8],[ESI+12]
JC .Ret: ; Leave flag reset if error.
JNZ .Ret: ; Leave flag reset if TRUE (NESTINGCHECK=ON, ZF=0).
SetSt [EDI+II.MfgExplicit],iiMfgNESTING_OFF ; If FALSE (NESTINGCHECK=OFF).
.Ret:RET
.iiMfsALIGN_Mask:
MOV EAX,[%Stm]
MOV EAX,[EAX+STM.Section]
Invoke ExpParseAlignment::,[ESI+8],[ESI+12],EAX
MOV [EDI+II.Align],EAX
RET
.MfgValue:
Invoke DictLookup::,EBX,[ESI+8],[ESI+12]
JC .W3742: ; Illegal !1S= value "!2S". Expected !3L.
OR [EDI+II.MfgExplicit],EAX
RET
.iiMfgCODE_Mask:
MOV EBX,DictIiMfCode:: ; Dictionary of CODE= values.
JMP .MfgValue:
.iiMfgDATA_Mask:
MOV EBX,DictIiMfData:: ; Dictionary of DATA= values.
JMP .MfgValue:
.iiMfgDISP_Mask:
MOV EBX,DictIiMfDisp:: ; Dictionary of DISP= values.
JMP .MfgValue:
.iiMfgIMM_Mask:
MOV EBX,DictIiMfImm:: ; Dictionary of IMM= values.
JMP .MfgValue:
.iiMfgDIST_Mask:
MOV EBX,DictIiMfDist:: ; Dictionary of DIST= values.
JMP .MfgValue:
.iiMfgADDR_Mask:
MOV EBX,DictIiMfAddr:: ; Dictionary of ADDR= values.
JMP .MfgValue:
.iiMfgSCALE_Mask:
MOV EBX,DictIiMfScale:: ; Dictionary of SCALE= values.
JMP .MfgValue:
.MfxValue:
Invoke DictLookup::,EBX,[ESI+8],[ESI+12]
JC .W3742: ; Illegal !1S= value "!2S". Expected !3L.
OR [EDI+II.MfxExplicit],EAX
RET
.iiMfxPREFIX_Mask:
MOV EBX,DictIiMfPrefix:: ; Dictionary of PREFIX= values.
JMP .MfxValue:
.iiMfxROUND_Mask:
MOV EBX,DictIiMfRound:: ; Dictionary od ROUND= values.
JMP .MfxValue:
.iiMfxMASK_Mask: ; Accept MASK=K0..K7 or numeric expression which evaluates to 0..7.
Invoke DictLookup::,DictIiMfMask::,[ESI+8],[ESI+12] ; Search for the enum values K0..K7.
JNC .M5:
Invoke ExpEvalNum::,[ESI+8],[ESI+12] ; If not enumerated value K0..K7, it may be octal digit or numeric expression.
JC .W3744: ; Value !1S=!2S=!3D is not acceptable, 0..7 expected.
.M5: CMP EAX,7 ; Void convert value 0..7 to iiMfxMASK_Mask.
JA .W3744: ; Value !1S=!2S=!3D is not acceptable, 0..7 expected.
BTS [EDI+II.MfxExplicit],EAX
RET
.iiMfxOPER_Mask: ; Accept OPER= arithmetic expression which evaluates to 0..7.
Invoke ExpEvalNum::,[ESI+8],[ESI+12]
JC .W3744: ; Value !1S=!2S=!3D is not acceptable, 0..7 expected.
CMP EAX,7
JA .W3744: ; Value !1S=!2S=!3D is not acceptable, 0..7 expected.
SHL EAX,28 ; Convert to iiMfxOPER_Mask.
RstSt [EDI+II.MfxExplicit],iiMfxOPER_Mask ; Clear any previous OPER= values.
SetSt EAX,iiMfxOPER_Used
SetSt [EDI+II.MfxExplicit],EAX
RET
; Boolean modifiers, EAX is the Mask in II.Mfx (two bits set).
.iiMfxBCST_Mask:
.iiMfxSAE_Mask:
.iiMfxEH_Mask:
.iiMfxZEROING_Mask:
BSF ECX,EAX ; ECX=Index of iiMfx*_0 flag.
Invoke ExpEvalBoolean::,[ESI+8],[ESI+12]
JBE .Reset: ; Set iiMfx*_0 on error (CF=1) or if evaluated FALSE (ZF=1).
INC ECX ; Index of iiMfx*_1 flag is ECX+1.
BTS [EDI+II.MfxExplicit],ECX ; Set iiMfx*_1.
RET
.Reset:
BTS [EDI+II.MfxExplicit],ECX ; Set iiMfx*_0.
RET
ENDP1 .EvalKey:
.90:EndProcedure StmGetIiModifiers
INC*, DEC*, PUSH*, POP*.
[.data]
ALIGN DWORD
Multiop:
o %FOR INC,INCB,INCW,INCD,INCQ,DEC,DECB,DECW,DECD,DECQ, PUSH,PUSHW,PUSHD,PUSHQ,POP,POPW,POPD,POPQ
DD Iig%o::
%ENDFOR o
MultiopEnd:
[.text]
StmMultiop? Procedure Stm
MOV EBX,[%Stm]
MOV EDI,Multiop
MOV ECX,(MultiopEnd-Multiop)/4
MOV EAX,[EBX+STM.OperationData]
REPNE SCASD
EndProcedure StmMultiop?
StmDisplayParsed Procedure Stm
MOV EBX,[%Stm]
BufferRetrieve [EBX+STM.ExpBuffer]
PUSH ECX,ESI
MOV EDX,ESP
Msg '1010',EDX ; **** DISPLAYSTM "!1S"'
POP ESI,ECX
JNSt [EBX+STM.Status],stmLabelPresent,.10:
LEA EDI,[EBX+STM.LabelPtr]
Msg '1020',EDI ; label="!1S"
.10: MOV EDX,1 ; Prefix number.
LEA EDI,[EBX+STM.Prefix1Ptr]
.15: MOV ECX,[EDI+4] ; Prefix size.
JECXZ .18:
Msg '1030',EDX,EDI ; prefix!1D="!2S"
.18: ADD EDI,3*4
INC EDX
CMP DL,4
JNA .15:
MOV EDX,=B"pseudo"
JSt [EBX+STM.Status],stmPseudoOperation,.20:
MOV EDX,=B"macro"
JSt [EBX+STM.Status],stmMacroOperation,.20:
MOV EDX,=B"machine"
JSt [EBX+STM.Status],stmIntelOperation,.20:
MOV EDX,=B"unknown"
.20: MOV ECX,[EBX+STM.OperationSize]
JECXZ .30:
LEA EDI,[EBX+STM.OperationPtr]
Msg '1040',EDX,EDI ; !1$ operation="!2S"
.30: MOV EDX,1
BufferRetrieve [EBX+STM.OrdBuffer]
.32: CMP EDX,[EBX+STM.NrOfOrdinals]
JA .40:
Msg '1050',EDX,ESI ; ordinal operand number=!1D,value="!2S"
ADD ESI,8
INC EDX
JMP .32:
.40: MOV EDX,1
BufferRetrieve [EBX+STM.KeyBuffer]
.42: CMP EDX,[EBX+STM.NrOfKeys]
JA .90:
LEA EDI,[ESI+8]
Msg '1060',ESI,EDI ; keyword operand,name="!1S",value="!2S"
ADD ESI,16
INC EDX
JMP .42:
.90:EndProcedure StmDisplayParsed
StmCheckLabel$ Procedure Stm
MOV EBX,[%Stm]
MOV ECX,[EBX+STM.LabelSize]
CMP ECX,1
JNE .90:
MOV ESI,[EBX+STM.LabelPtr]
LODSB
CMP AL,'$'
JNE .90:
JNSt [EBX+STM.Status],stmLabelIsPublic,.90:
Msg '2711' ; Special dynamic symbol $ cannot be made global.
CMP EAX,EAX ; Set ZF=1.
.90:EndProcedure StmCheckLabel$
ENDPROGRAM stm