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. INCLUDEHEAD \ ; Include headers of another modules used in this module. 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, \ syswin.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 %OtherVar
are 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 %OtherVar
the 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 JECXZ .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