| Index | Manual | Download | Source | Macros | Embedded word Case ins.
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 used in this source.
                    chunk.htm,ctx.htm,dict.htm,ea.htm,eaopt.htm,exp.htm,ii.htm,lst.htm,msg.htm,pgm.htm, \
                    pgmopt.htm,reloc.htm,sss.htm,sym.htm,var.htm

    stm HEAD ; Start of module interface.

↑ STM
  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:
  - Line-feed or `%TxtEnd`.
  - Unquoted comma `,`.
  - Unquoted semicolon `;`.
  - Unquoted backslash `\` at the beginning of field when `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

  - Unquoted and unbracketed colon(s) `:`
  - Unquoted and unbracketed white-space `` .
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
         TEST ECX
         JZ .R7:                                     ; If empty section.
         MOV EAX,[%DumpWidth]
         SUB EAX,4
         SUB EAX,[%Room4Value]
         JLE .R7:
         MOV ESI,[ECX+SSS.NamePtr]
         MOV ECX,[ECX+SSS.NameSize]
         CMP EAX,ECX
         JAE .R6:                                    ; Jump if the whole section name fits to dump width.
         LEA EDX,[ESI+ECX]
         SHR EAX,1                                   ; Long section name will be from-the middle-shortened.
         ADD [%DumpPos],EAX
         StreamStore [Src.Lst.Stream::],ESI,EAX
         StreamStoreWord [Src.Lst.Stream::],'~~'
         ADDD [%DumpPos],2
         MOV ECX,[%DumpWidth]
         SUB ECX,[%DumpPos]
         SUB ECX,[%Room4Value]
         DEC ECX
         MOV ESI,EDX
         SUB ESI,ECX
     .R6:StreamStore [Src.Lst.Stream::],ESI,ECX
         ADD [%DumpPos],ECX
     .R7:StreamStoreByte [Src.Lst.Stream::],']'
         INCD [%DumpPos]
         RET
        ENDP1 StmListing.StoreSection:

    StmListing.StoreOrg: PROC1 ; Store '|' (left dump column separator) followed by hexa offset [%Org] and ':', initialize [%DumpPos].
         MOVD [%DumpPos],2
         StreamStoreByte [Src.Lst.Stream::],'|'
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.O9:
         INCD [%DumpPos]
         MOV EAX,[%Org]
         MOV ECX,4                                   ; Width of dumped address is 16 bits in 16bit segment, otherwise 32 bits.
         JNSt [%SssStatus],sssWidth16,.O2:
         MOV CL,2
         SHL EAX,16
     .O2:ROL EAX,8
         CALL StmListing.StoreHexa:
         LOOP .O2:
     .O3:StreamStoreByte [Src.Lst.Stream::],':'      ; Address:data separator.
     .O9:RET
       ENDP1 StmListing.StoreOrg:

    StmListing.StoreHexa: PROC1 ; Store one hexa byte AL to listing stream. Advance [%DumpPos] by 2. Destroys EDX.
          PUSH EAX
           AND AL,0x0F
           LEA EDX,[%DumpHexa]
           ADD AL,0x90
           DAA
           ADC AL,0x40
           DAA
           MOV [EDX+1],AL
          POP EAX
          PUSH EAX
           SHR EAX,4
           AND AL,0x0F
           ADD AL,0x90
           DAA
           ADC AL,0x40
           DAA
           MOV [EDX+0],AL
           StreamStore [Src.Lst.Stream::],EDX,2
          POP EAX
          ADDD [%DumpPos],2
          RET
         ENDP1 StmListing.StoreHexa:

    StmListing.NextReloc PROC1 ; Update %RelocOrg, %Decorators, RelocPtr.
     ; Input: -     Output: EAX,ECX,ESI undefined.
     ; This subproc is called from .StoreDumpLine right after decorator from [%Decorators] has been listed
     ; (either opening or closing bracket), due to [%DumpOrg] has just reached [%RelocOrg].
     ; [%Decorators] contains in LSB current decorator char (bracket) and it will be byte-shifted for the next (closing) bracket.
     ; [%RelocOrg] will be increased by relocation width.
     ; If .NextReloc is called after the last closing bracket, it advances ESI to the next RELOC and prepares
     ; [%Decorators] and [%RelocOrg] for the next relocation, if some exists.
     ; Example of dump with relocations in 16bit addressing mode:
     ; 12(3456)       relocRel   Self-relative relocation.  [%Decorators]='()'
     ; 12[3456]       relocAbsVA   Segm-relative relocation.  [%Decorators]='[]'
     ; 12{3456}       relocPara  Paragraph addr.relocation. [%Decorators]='{}'
     ; 12[3456]{789A} relocFar   Far pointer relocation.    [%Decorators]='[]{}'
     ; 1234<5         relocDisp8N Disp8*32 decoration.      [%Decorators]='<5'                                        ; >>
          MOV EAX,[%Decorators]                      ; Decorator in AL has just been listed.
          MOV ESI,[%RelocPtr]                        ; ESI is now the current RELOC record.
          MOV ECX,EAX
          JECXZ .N1:                                 ; If there's no decorator left, i.e. if the relocation ESI has just been completely decorated.
          SHR EAX,8                                  ; Otherwise prepare the next decorator (usually a closing bracket) to LSB.
          MOV [%Decorators],EAX
          TEST AL                                    ; No more markers?
          JNZ .N5:                                   ; If the decoration of relocation ESI is still pending.
     .N1: ADD ESI,SIZE#RELOC                         ; All decorators from this relocation ESI are listed, prepare for the next RELOC.
          DEC EAX                                    ; Set RelocOrg to -1 when there are no more relocations in this statement.
          CMP ESI,[%RelocEnd]
          JNB .N2:                                   ; If there are no more relocations in this statement.
          MOV [%RelocPtr],ESI
          ; New relocation starts. ESI is the current RELOC to dump.
          CALL StmListing.GetDecorators
          MOV [%Decorators],EAX
          MOV EAX,[ESI+RELOC.OrgLow]                 ; EAX=Unpatched origin, relative to stm data. If dumping literal, it's relative to the section data.
          JSt [Src.Lst.Status::],lstLiteral,.N2:
          ADD EAX,[EBX+STM.OffsetLow]
     .N2: MOV [%RelocOrg],EAX
          RET
     .N5: JNSt [ESI+RELOC.Status],relocFar, .N7:
          CMP AL,'{'                                 ; Is it the segment part of far pointer decoration?
          JE .N9:                                    ; In that case leave [%RelocOrg] unchanged, so the decorator { will immediately follow ].
          CMP AL,'}'                                 ; Is it the end of segment part of far pointer decoration?
          MOV ECX,2                                  ; If yes, the closing bracket '}' will follow after 2 dumped bytes of segment value.
          JE .N8:
     .N7: CALL StmListing.GetDecorators              ; Otherwise find the distance of the next decorator.
     .N8: ADD [%RelocOrg],ECX
     .N9: RET
         ENDP1 StmListing.NextReloc:

    StmListing.GetDecorators: PROC1 ; Get the set of listing decorator characters and relocation size.
          ; Input:  ESI=^RELOC.
          ; Output: EAX=The set of relocation decorators. The last one is in LSB (AL).
          ;         ECX=next decorator distance in dumped bytes (0,1,2,4,8).
          MOV EAX,[ESI+RELOC.Status]
          MOV ECX,EAX
          AND ECX,relocWidthMask
          SHR ECX,19                                 ; Convert relocWidthMask to size 2,4,8.
          JNZ .G5:
          INC ECX
    .G5:  JSt EAX,relocAbsVA,.relocAbsVA:
          JSt EAX,relocRel,  .relocRel:
          JSt EAX,relocPara, .relocPara:
          JSt EAX,relocFar,  .relocFar:
          JSt EAX,relocDisp8N,.relocDisp8N:
    .relocResolved:
          XOR EAX,EAX
          XOR ECX,ECX
          RET
    .relocDisp8N:
          XOR ECX,ECX
          AND EAX,relocDisp8N ; EAX=0x1000_0000..0x7000_0000.
          SHR EAX,20
          OR AH,'0'
          MOV AL,'<'                                                                 ; >
          RET
    .relocAbsVA:
          MOV EAX,[ESI+RELOC.Status]
          AND EAX,relocExtAttr
          CMP EAX,dictAttrPARA<<16                                                   ; >>
          MOV EAX,'[]'
          JE .relocPara:
          RET
    .relocRel:
          MOV EAX,'()'
          RET
    .relocPara:
          MOV CL,2 ; relocPara {1234}.
          MOV EAX,'{}'
          RET
    .relocFar:
    ;     MOV CL,2 ; relocWidth16 [1234]{5678}.
    ;     JSt EAX,relocWidth16, .Far:
    ;     MOV CL,4 ; relocWidth32 [12345678]{9ABC}.
    ;.Far:
          MOV EAX,'[]{}'
          RET
        ENDP1 StmListing.GetDecorators:

    StmListing.StuffDumpEnd: PROC1 ; Keep storing spaces or tildes until the end of dump column.
         MOV DL,'~'
         JSt [Src.Lst.Status::],lstTilde,.E2:
         MOV DL,' '
     .E2:MOV ECX,[%DumpPos]
     .E3:CMP ECX,[%DumpWidth]
         JAE .E9:
         StreamStoreByte [Src.Lst.Stream::],DL
         INC ECX
         JMP .E3:
     .E9:RET
        ENDP1 StmListing.StuffDumpEnd:

    StmListing.StoreSrcLine: PROC1 ; Store one source physical line to listing stream, advance [%SrcPtr], decrement [%SrcLines].
          MOV ESI,[%SrcPtr]
          MOV ECX,[%SrcEnd]
          SUB ECX,ESI
          JNA .80:
          PUSH EDI
           MOV EDI,ESI
           MOV AL,10 ; LineFeed.
           REPNE SCASB
           MOV ECX,EDI
           MOV [%SrcPtr],EDI
           SUB ECX,ESI
          POP EDI
          CALL StmListing.StreamTrim:
     .80: DECD [%SrcLines]
          RET
         ENDP1 StmListing.StoreSrcLine:

    StmListing.StoreDumpLine: PROC1 ; Store one row of dump bytes and then empty stuff until DumpPos will reach DumpWidth.
                         ; Column separator is expected to be stored to stream after .StoreDumpLine call.
          RstSt [Src.Lst.Status::],lstTilde
          JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.D9:
     .D0: CMPD [%DumpBytes],0
          JG .D2: ; If some bytes left unstored.
          ; All dumped. Reloc marker ( ) might have been left open.
          MOV EAX,[%Decorators]
          CMP AL,0
          JE .D9:
          CMP AL,'['
          JE .D9:
          CMP AL,'('
          JE .D9:
          CMP AL,'{'
          JE .D9:
     .D1: MOV EAX,[%DumpPos]
          INC EAX
          CMP EAX,[%DumpWidth]                        ; Is there room for closing decorator in this physical line?
          JA .D9:
          JMP .D3:
     .D2: MOV EAX,[%DumpPos]
          ADD EAX,2
          CMP EAX,[%DumpWidth]                        ; Is there enough room for the hexabyte in this physical line?
          JA .D7:                                     ; If not, quit with the line.
          CMPD [%DumpBytes],1
          JE .D3:
          CMPD [%SrcLines],1
          JA .D3:
          JSt [%EaoptStatus],eaoptDUMPALL,.D3:
          ; No more source lines but still may need to dump some data.
          INC EAX
          CMP EAX,[%DumpWidth]
          JA .D8:                                     ; Not all data can be dumped, mark that with lstTilde.
     .D3: MOV EAX,[%Org]
          CMP EAX,[%RelocOrg]                         ; Has dumped origin reached position of a relocable address?
          JB .D4:                                     ; Jump if not yet reached.
          MOV EAX,[%Decorators]                       ; Relocation begining or end is due, insert one of ()[]{}.
          TEST AL
          JZ .DN:
          StreamStoreByte [Src.Lst.Stream::],AL
          INCD [%DumpPos]
     .DN: CALL StmListing.NextReloc:
          JMP .D0:
     .D4: CMPD [%DumpBytes],0
          JBE .D9:
          MOV ESI,[%DumpPtr]
          LODSB
          MOV [%DumpPtr],ESI
          JSt [%SssPurpose],sssPurposeInitMask, .D5:
          StreamStoreWord [Src.Lst.Stream::],'..'    ; In BSS segment store .. instead of hexa byte.
          ADDD [%DumpPos],2
          JMPS .D6:
     .D5: CALL StmListing.StoreHexa:
     .D6: INCD [%Org]
          CMPD [%DumpBytes],0
          JZ .D0:
          DECD [%DumpBytes]
          JMP .D0:
     .D7: CMPD [%SrcLines],1
          JA  .D9:                                   ; While unlisted source lines exist, continue dumping data.
          ; No more source lines are available. Repeated dump column will continue only if DUMPALL=ON, otherwise lstTilde.
          JNSt [%SssPurpose],sssPurposeCODE|sssPurposeDATA|sssPurposeRODATA,.D8: ; Shorten dump with tilde in BSS section (regardless of DUMPALL).
          JSt [%EaoptStatus],eaoptDUMPALL,.D9:       ; Shorten dump with tilde when DUMPALL=OFF.
     .D8: SetSt [Src.Lst.Status::],lstTilde
     .D9: CALL StmListing.StuffDumpEnd:
          RET
         ENDP1 StmListing.StoreDumpLine:

    StmListing.StoreSetLine: PROC1 ; Store one row of dump bytes, then store empty stuff until DumpPos will reach DumpWidth.
                        ; Column separator is expected to be stored to stream after .StoreSetLine call.
          RstSt [Src.Lst.Status::],lstTilde
          StreamStoreByte [Src.Lst.Stream::],'|'     ; Machine comment in the 1st dump column.
          MOVD [%DumpPos],2
          JSt [Src.Lst.Status::],lstTRUE|lstFALSE,.S0:
          JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.S9:
     .S0: JNSt [Src.Lst.Status::],lstTRUE,.S1:       ; In boolean-type statements list TRUE or FALSE in dump column.
          StreamStore$ [Src.Lst.Stream::],=B"TRUE"
          ADDD [%DumpPos],4
          JMPS .S2:
     .S1: JNSt [Src.Lst.Status::],lstFALSE,.S2:
          StreamStore$ [Src.Lst.Stream::],=B"FALSE"
          ADDD [%DumpPos],5
     .S2: RstSt [Src.Lst.Status::],lstTilde+lstTRUE+lstFALSE
          CMPD [%DumpBytes],0
          JNG .S9:
          MOV EAX,[%DumpPos]
          ADD EAX,2
          CMP EAX,[%DumpWidth]
          JA .S7:
          CMPD [%DumpBytes],1
          JE .S4:                                     ; If no more emitted bytes to dump.
          CMPD [%SrcLines],1
          JA .S4:                                     ; If no more source physical lines to list.
          JSt [%EaoptStatus],eaoptDUMPALL,.S4:
          INC EAX
          CMP EAX,[%DumpWidth]
          JA .S8:
     .S4: MOV ESI,[%DumpPtr]
          LODSB
          MOV [%DumpPtr],ESI
     .S6: CALL StmListing.StoreHexa:
          DECD [%DumpBytes]
          JMP .S2:
     .S7: CMPD [%SrcLines],1
          JA  .S9:
          JSt [%EaoptStatus],eaoptDUMPALL,.S9:
     .S8: SetSt [Src.Lst.Status::],lstTilde
     .S9: CALL StmListing.StuffDumpEnd:               ; Fill the rest of dump column with spaces.
          RET
         ENDP1 StmListing.StoreSetLine:
    .99:EndProcedure StmListing

↑ 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▲