EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

stm.htm
Class
STM
Encodings
StmEnc
StmEncTemp
Macros
StmInStruc
Procedures
StmClean
StmCreate
StmDestroy
StmDisplayParsed
StmExecute
StmExpandField
StmFlush
StmGetIiModifiers
StmCheckFields
StmCheckLabel$
StmListing
StmMultiop?
StmParse
StmParseField
StmParsePcPseudo
StmParseSET

Class STM represents one assembler statement. Each statement will be

  1. fetched from source with SrcFetchLine
  2. parsed with StmParse
  3. executed with StmExecute
  4. written to listing with StmListing
  5. flushed to segment with StmFlush
Statement assembly object model
EaMain EaCreate EaAssemble Src SrcCreate SrcAssemble Stm StmClean StmParse StmExecute StmListing StmFlush SrcDestroy EaDestroy

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
Class STM describes one statement of source code.
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
↑ StmEnc
Encoding of STM.Status flags used by pseudoinstruction handlers when creating a symbol from the statement 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.
↑ StmEncTemp
Encoding of STM.Flags used temporarily by statement parser.
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 Stm, Target
Macro StmInStruc will check whether the statement is by mistake used inside structure definition and jump to Target if so.
Input
Stm is pointer to the current statement.
Target is label where to jump on error.
Output
-
On error
E7125 is reported when inside a structure, continued at %Target.
Example
StmInStruc EBX, .90:
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 Stm
StmCreate clears the STM object and reserves its buffers.
Input
Stm Pointer to an allocated STM object. Its contents is discarded.
Output
- STM object ready for parsing.
Error
- Errors are not expected.
See also
StmDestroy, StmClean
Invokes
EaBufferReserve
Invoked by
ChunkSubHead EaIniAssemble ExpStoreInstr PgmListLiterals SrcAssemble
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 Stm
Empties the Stm structure and its buffers. Similar to StmCreate but faster.
Input
Stm is pointer to STM as returned from StmCreate.
Output
Stm cleaned.
See also
StmCreate, StmDestroy.
Invoked by
ChunkSubHead PgmListLiterals SrcAssemble
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 Stm
StmDestroy will release buffers in STM object and clear its contents.
Input
Stm Pointer to a STM.
Output
-
Error
- Errors are not expected.
See also
StmCreate
Invokes
EaBufferRelease
Invoked by
ChunkSubHead EaIniAssemble ExpStoreInstr PgmListLiterals SrcAssemble
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
↑ StmExecute Stm
StmExecute does the actual statement job: emits machine code, modifies context stack etc.

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.

Input
Stm Parsed statement.
Output
Stm.LineNext will point to the next statement to assemble, usually 0 (which means identical with Stm.LineEnd) unless Stm is an endblock statement and assembly should continue at the beginblock statement.
Other €ASM objects may be modified, depending on the operation.
Error
SrcAssemble
See also
StmParse, StmFlush.
Invokes
IiAssemble IiAssembleMultiop MacExpand PseudoNoOperation StmMultiop?
Invoked by
SrcAssemble
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
↑ StmExpandField Stm, FieldPtr, FieldEnd
The whole contents of input field will be stored to 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.
Special cases:
  1. When Stm.Flags:stmtProgram&&stmtOutFile are both set, variable %& is not expanded but its percent sign is doubled to %%& instead.
  2. When Stm.Status:stmIncludeAny is set, variable %& is not expanded but its percent sign is doubled to %%& instead.
  3. The first %variable is not expanded when Stm.Flags:stmtSETany is set. This flag is reset once it is used.
  4. No %variable is expanded when Stm.Flags:stmtSETLorS is set. This flag is not reset.
Input
Stm Pointer to the STM object.
FieldPtr The first character of the field.
FieldEnd Behind the last character of the field.
Output
STM.ExpBuffer is appended with expanded field contents.
Error
Errors are reported with macro Msg.
See also
VarExpandField.
Example
; Assume %Member is assigned with the text LinePtr. FieldPtr FieldEnd | | [EBX+STM.%Member] Stm.ExpBuffer will be appended with text [EBX+STM.LinePtr].
Invokes
EaBufferRelease EaBufferReserve VarExpandField VarParseName
Invoked by
StmParse
Tested by
t2408
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 like PROGRAM 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 like INCLUDE "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
↑ StmParse Stm, LinePtr, ChunkPtr
Horizontally parses one assembler statement into fields and puts the result in Stm object.
The first field-parsing pass resolves line continuation and expands %variables. In the second pass the expanded statement is finally parsed into fields.
StmParse also preloads its members .Program, .Section, .Offset with current values, although they may be changed later in statement execution.
Input
Stm is pointer to a target STM structured variable. It should be empty with all buffers allocated, as constructed by StmCreate or StmClean.
LinePtr Start of the statement - pointer into the memory-mapped source file.
It may be 0, the 1st source line is returned in this case.
StmParse will fetch successive physical lines by itself when line-continuation is detected.
ChunkPtr pointer to CHUNK where the search for line should begin. The search starts with the first chunk on Src.ChunkList when ChunkPtr is NULL.
Output
CF=0 Stm is filled with parsed fields. Registers unchanged.
CF=1 on end of source. Contents of Stm is unchanged.
Error
Parsing errors are reported using macro Msg.
Invokes
CtxPeek CtxStatusAll DictLookup DictLookupIi ExpParseIdentifier MacFind PgmGetCurrent SrcFetchLine SssGetSegm StmExpandField StmParseField StmParsePcPseudo StmParseSET
Invoked by
ChunkSubHead ExpStoreInstr SrcAssemble
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
↑ StmParseField Stm, TxtPtr, TxtEnd
StmParseField will find the end of one field in unexpanded or expanded statement.
If the statement contains at least one % or \, StmParseField needs to be called twice for each field, because %variables are not expanded yet in the first pass and their expansion may change the label-prefix-operation-operands assignment.
A field can be terminated with:

If operand field is not expected (Stm.Flags:stmtOperationParsed is not set yet), then it also can be terminated with

Input
Stm Pointer to STM which the statement is parsed to.
TxtPtr Start of the field in the statement. Leading white spaces will be ignored.
TxtEnd End of physical line where the parsing stops.
Output
EAX=pointer to the end of field, behind its last character. Always between TxtPtr and TxtEnd.
If the field is terminated with line-feed, white-space, comma , backslash \ or semicolon ;, EAX points to that character.
If the field is terminated with colon(s) :, EAX points behind the last colon.
Errors
are not detected, syntax ignored.
Example
REPNE:SCASB | | aLabel:: PUSH EAX , Ofs: ; Comment. | | | | Lbl%N[1 .. ";"-","] DD \ Comment. | |
Invoked by
StmParse
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
↑ StmParsePcPseudo Stm, TxtPtr, TxtEnd
StmParsePcPseudo reads expanded text of the statement and sets 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.
Input
Stm Parsed statement.
TxtPtr Pointer to expanded source text (after the 1st parsing pass).
TxtEnd End of source line.
Output
Flag Stm.Status:stmPseudoBlock is modified.
Error
Errors are not detected.
See also
StmParseSET.
Invokes
DictLookup
Invoked by
StmParse
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
↑ StmParseSET Stm, LabelPtr
StmParseSET detects special case when the %variable should not expand in statement, which starts with percent sign. This happens in operations %SET/A/B/C/E/2/S/L.
This procedure investigates whether the operation field is %SET* and sets Stm.Flags:stmtSETany in this case.
If the operation field is %SETS or %SETL, Stm.Flags:stmtSETLorS is set, too.
StmParseSET also sets ctxMacLabel in macro-definition context if the statement starts with %:.
Input
Stm Pointer to STM, which may not be parsed yet.
LabelPtr Pointer to the first non-white character, which should be percent sign %.
Output
Stm.Flags stmtSETany and stmtSETLorS modified.
Error
Errors are not reported.
Example
LabelPtr | %SomeVar %SETS %OtherVar stmtSETany + stmtSETLorS will be set.
Invokes
CtxFind DictLookup VarParseName
Invoked by
StmParse
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 Stm, Pattern
StmCheckFields will inspect the number of fields in the statement and issue an error when other than expected.
Input
Stm Pointer to a parsed statement (STM object).
Pattern is doubleword with four characters describing expected number of fields.
The order of pattern characters is label, prefix, ordinal, keyword.
Possible characters are:
* 0 or more fields (prefix, ordinal, keyword).
? 0 or 1 field (label, ordinal).
+ 1 or more fields (ordinal).
0 0 field (label, prefix, ordinal, keyword).
1 1 field (label, ordinal).
2 2 fields (ordinal).
3 3 fields (ordinal).
Output
CF=0 if no error.
Error
CF=1 if wrong number of fields. Error is reported with Msg (E6810..E6840).
Example
Invoke StmCheckFields, EBX, '?02*' ; Statement may have a label, no prefix, and must have 2 ordinal operands. ; Number of keywords is unimportant.
Invoked by
ChunkInclude MacExpand PseudoALIGN PseudoData PseudoENDHEAD PseudoENDPROC PseudoENDPROC1 PseudoENDPROGRAM PseudoENDSTRUC PseudoEQU PseudoEUROASM PseudoGROUP PseudoHEAD PseudoLINK PseudoNoOperation PseudoPROC PseudoPROC1 PseudoPROGRAM PseudoSEGMENT PseudoSTRUC PseudoScope PseudopcCOMMENT PseudopcDISPLAY PseudopcDROPMACRO PseudopcELSE PseudopcENDCOMMENT PseudopcENDFOR PseudopcENDIF PseudopcENDMACRO PseudopcENDREPEAT PseudopcENDWHILE PseudopcERROR PseudopcEXITFOR PseudopcEXITMACRO PseudopcEXITREPEAT PseudopcEXITWHILE PseudopcFOR PseudopcIF PseudopcMACRO PseudopcREPEAT PseudopcSET PseudopcSET2 PseudopcSETA PseudopcSETB PseudopcSETC PseudopcSETE PseudopcSETL PseudopcSETS PseudopcSETX PseudopcSHIFT PseudopcWHILE
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 Stm
StmListing completes one listing statement and writes it to Src.Lst.Stream. It is invoked from SrcAssemble in the final pass.
Input
Stm Ptr to the statement to list.
Output
Listing line(s) are written to Src.Lst.Stream.
Error
CF=1 Errors are reported with macro Msg.
Example
| Dump column | Source column +---DUMPWIDTH=27----------+ |00410001:[.data] ; <- Lst line inserted if section changed. |00410001:000000 ; <- Lst line inserted if AUTOALIGN=ON. |00410004:78563412 |Lb1: DD 0x12345678 |00410008:050505050505050~| DB 13*B 5, D 1.001E2 <- Dump column shortened if DUMPALL=OFF. |##W2210 Precision lost in calculation with FP number rounded to integer. <- Inserted msg. |313233 | %Var %SETA 100+23
See also
PgmListLiterals
Invokes
CtxPeek EaBufferRelease EaBufferReserve SssEmitAlignment
Invoked by
PgmListLiterals SrcAssemble
Tested by
t2115 t2210 t2222
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
↑ StmFlush Stm
StmFlush copies relocations from Stm.RelocBuffer to Stm.Section.RelocBuffer and patches their origin by Stm.Section.Org.
StmFlush updates current program section from Stm.Section.
Then it copies the contents of Stm.EmitBuffer to Stm.Section.EmitBuffer and updates Sss.Org, Sss.Top.
If Stm.Flags:stmtNotBSS is set, it will set Stm.Section.status:sssNotBSS, too.
StmFlush is invoked from SrcAssemble when the statement has been parsed and executed.
Input
Stm Parsed and executed statement.
Output
-
Error
Errors are reported with macro Msg.
See also
SssEmit.
Invokes
SssEmit
Invoked by
SrcAssemble
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
↑ StmGetIiModifiers Stm, Ii
StmGetIiModifiers assembles machine instruction modifiers specified as statement keywords 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.
Input
Stm is pointer to the parsed STM.
Ii is pointer to the II object where flags should be stored.
Output
Assembled keyword values are set to II members .MfgExplicit, .MfxExplicit and .Align.
Error
Warnings W3740..W3744 are reported with macro Msg . Expected modifiers should be explicitly allowed with IiAllowModifier , otherwise W3741. Modifiers ALIGN= and NESTINGCHECK= do not need to be explicitly allowed.
Example
Invoke StmGetIiModifiers, EBX, EDI
See also
IiModifiersToKeys.
Invokes
DictLookup ExpEvalBoolean ExpEvalNum ExpParseAlignment
Invoked by
IiAssemble PseudoENDPROC PseudoENDPROC1 PseudoPROC PseudoPROC1 PseudoSTRUC
Tested by
t5135
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
↑ StmMultiop? Stm
StmMultiop? checks if the machine instruction parsed in Stm is one of multioperand instructions INC*, DEC*, PUSH*, POP*.
Input
Stm Pointer to parsed statement.
Output
ZF=1 if operation is Multiop instruction, otherwise ZF=0.
Invoked by
ExpStoreInstr StmExecute
[.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 Stm
StmDisplayParsed issues messages D1010..D1017 which show how was the statement parsed into fields.
Input
Stm Pointer to parsed statement.
Output
-
Example
EUROASM DisplayStm=ON
Invoked by
SrcAssemble
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$ Stm
StmCheckLabel$ test the label field of Stm if it specifies a special dynamic symbol $
Input
Stm Pointer to a parsed statement STM.
Output
ZF=0 The label field is not $.
ZF=1 The label field is $.
Warning
W2711 is emitted if the label terminates with two or more colons.
Example
Invoke StmCheckLabel$, EBX JE .90: ; Ignore label $. Invoke SymCreate...
Invoked by
IiAssemble IiAssembleMultiop PseudoData PseudoEQU PseudoEXTERN PseudoGLOBAL PseudoNoOperation PseudoPUBLIC
Tested by
T2383
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

▲Back to the top▲