| Index | Manual | Download | Source | Macros | Embedded word Case ins.
Sitemap | Links | Forum | Tests | Projects

# pseudo.htm
Procedures
PseudoALIGN
PseudoD
PseudoData
PseudoDB
PseudoDD
PseudoDQ
PseudoDS
PseudoDT
PseudoDU
PseudoDW
PseudoENDHEAD
PseudoENDPROC
PseudoENDPROC1
PseudoENDPROGRAM
PseudoENDSTRUC
PseudoEQU
PseudoEUROASM
PseudoEXPORT
PseudoEXTERN
PseudoGLOBAL
PseudoGROUP
PseudoHEAD
PseudoIMPORT
PseudoINCLUDE
PseudoINCLUDE1
PseudoINCLUDEBIN
PseudoINCLUDEHEAD
PseudoINCLUDEHEAD1
PseudoLINK
PseudoNoOperation
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
PseudopcUNTIL
PseudopcWHILE
PseudoPROC
PseudoPROC1
PseudoPROGRAM
PseudoPUBLIC
PseudoScope
PseudoSEGMENT
PseudoSTRUC

Following procedures – pseudoinstruction handlers – do the actual pseudoinstruction job. They are called with statement parsed from source text into STM structure. Pseudoinstruction handlers are called regardless of `CtxStatus:ctxNoEmit` state. In nonemitting state the handler does nothing unless it is the same block/endblock type, in which case it updates the context.

Pseudoinstruction assembly object model
  EaMain EaCreate EaAssemble Src SrcCreate SrcAssemble Stm StmClean StmParse StmExecute pseudoinstruction Pseudohandler StmListing StmFlush SrcDestroy EaDestroy

    pseudo PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32,MAXPASSES=64
           INCLUDEHEAD euroasm.htm, \  Interface (structures, symbols and macros) of other modules used in this source.
                       ctx.htm,chunk.htm,dict.htm,ea.htm,eaopt.htm,exp.htm,ii.htm,lst.htm,mac.htm, \
                       member.htm,msg.htm,pass.htm,pgm.htm,pgmopt.htm,reloc.htm,sss.htm,stm.htm,sym.htm

    pseudo HEAD
             ; This modul has no interface.
           ENDHEAD pseudo

    [.text]

↑ PseudoALIGN Stm
  Pseudoinstruction ALIGN handler.
Manual
  ALIGN
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  ExpAlign ExpParseAlignment SssEmitAlignment StmCheckFields
Tested by
  t2508

    PseudoALIGN Procedure Stm
    Align1 LocalVar ; 1.argument value 0..512. Must be power of 2.
    Align2 LocalVar ; 2.argument value 0..511. Must be below %Align1.
         MOV EBX,[%Stm]
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90:
         MOV EDI,[EBX+STM.Program]
         TEST EDI
         JZ .90:
         MOV ESI,[EDI+PGM.CurrentSect] ; ALIGN does not change autosegment value.
         TEST ESI
         JZ .90:                       ; When the current segment was not established yet.
         MOV EAX,[ESI+SSS.OrgLow]
         MOV EDX,[ESI+SSS.OrgHigh]
         MOV [EBX+STM.Section],ESI
         MOV [EBX+STM.OffsetLow],EAX
         MOV [EBX+STM.OffsetHigh],EDX
         Invoke StmCheckFields::, EBX,"00+0"
         BufferRetrieve [EBX+STM.OrdBuffer]
         TEST ECX
         JZ .90: ; If no ordinals, do nothing.
         LODSD ; Ptr to %1.
         MOV EDI,EAX
         LODSD ; Size of %1.
         MOV EDX,[EBX+STM.Section]
         Invoke ExpParseAlignment::,EDI,EAX,EDX
         JC .90:
         MOV [%Align1],EAX
         MOVD [%Align2],0
         BufferRetrieve [EBX+STM.OrdBuffer]
         CMP ECX,16
         Msg cc=A,'3413' ; Pseudoinstruction ALIGN expects one or two operands.
         JB .30: ; If one operand only.
         ; ALIGN with two operands.
         ADD ESI,8 ; Skip %1.
         LODSD
         MOV EDI,EAX
         LODSD
         Invoke ExpParseAlignment::,EDI,EAX,0
         MOV [%Align2],EAX
         JC .30: ; Ignore wrong %2.
         CMP EAX,EDX      ; EAX is value of 2nd operand. It should be below 1st operand.
         Msg cc=NB,'3412',EDX,EAX ; Value of the 2nd operand (!2D) should be below the 1st operand (!1D). Ignored.
     .30:Invoke ExpAlign::,[EBX+STM.OffsetLow],[%Align1],[%Align2] ; Return ECX=size of alignment stuff.
         JECXZ .90: ; No alignment necessary.
         MOV EDI,[EBX+STM.Program]
         XOR EDX,EDX ; DL=alignment stuff.
         Invoke SssEmitAlignment::,[EDI+PGM.CurrentSect],ECX,[EBX+STM.EmitBuffer]
    .90:EndProcedure PseudoALIGN

↑ PseudoData Stm
  Procedure PseudoData is the common pseudoinstruction handler for data definition. It is invoked by PseudoD* with `Stm.Status` initialized with D mnemonic suffix (B,U,W,D,Q,T,O,Y,Z,I,S) or 0 if no suffix is used. Operands without explicit datatype specification will inherit datatype from D suffix. Datatype of quoted string without explicit specification (e.g. `D "string"`) is 'B' or 'U', depending on EUROASM %^UNICODE option, if no explicit datatype is specified by D suffix.
Input
  Stm is pointer to the statement (STM structure).
Output
  Members of Stm are updated: Stm.EmitBuffer and Stm.RelocBuffer, Stm.Flags:stmtNotBSS.
Error
  CF=1 Errors are reported with macro Msg.
Invokes
  CtxCreate DictLookup DictSearchByData EaBufferRelease EaBufferReserve ExpAlign ExpEvalData ExpParseData MemberAdd MemberCreate MemberUpdate SssCheckPurpose SssGetSegm StmCheckFields SymCreate
Invoked by
  PseudoD PseudoDB PseudoDD PseudoDI PseudoDO PseudoDQ PseudoDS PseudoDT PseudoDU PseudoDW PseudoDY PseudoDZ
Tested by
  t2480 t2481 t2482 t2500 t2501 t2506

    PseudoData Procedure Stm
    DataExp       LocalVar Size=SIZE#EXP ; EXP object used to parse the ordinal operand of Stm, such as 4*D 0.
    OrdPtr        LocalVar ; Pointer to the operand text.
    OrdSize       LocalVar ; Size of the operand text.
    OrdBufPtr     LocalVar ; Pointer to an array of pairs of DWORD with ordinal operand (%OrdPtr,%OrdSize).
    OrdBufSize    LocalVar ; 0,8,16,.. depending on the number of ordinals in the statement.
    DataEmitBuf   LocalVar ; ^BUFFER for data emitted by D pseudoinstruction. Empty in BSS section.
    DataRelocBuf  LocalVar ; ^BUFFER for RELOC records required by D pseudoinstruction (in the final pass).
    StrucEmitBuf  LocalVar ; ^BUFFER for data emitted by a structure member.
    StrucRelocBuf LocalVar ; ^BUFFER for RELOC records required by a structure member.
        MOV EBX,[%Stm]
        LEA EDI,[%DataExp]
        JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90: ; Do nothing in nonemitting state.
        Invoke EaBufferReserve::,%^PROC
        MOV [%DataEmitBuf],EAX
        Invoke EaBufferReserve::,%^PROC
        MOV [%DataRelocBuf],EAX
        Invoke EaBufferReserve::,%^PROC
        MOV [%StrucEmitBuf],EAX
        Invoke EaBufferReserve::,%^PROC
        MOV [%StrucRelocBuf],EAX
        RstSt [EBX+STM.Flags],stmtNotBSS          ; Any initialized static data found in ExpEvalData may set this flag later.
        BufferRetrieve [EBX+STM.OrdBuffer]        ; Array of 2*DWORDs (pointer to ordinal + size of ordinal).
        MOV [%OrdBufPtr],ESI
        MOV [%OrdBufSize],ECX
    .10:; The code between .10: and .22: is a loop for processing all ordinal operands.
        MOV ECX,[%OrdBufSize]
        MOV ESI,[%OrdBufPtr]
        TEST ECX
        JZ .22:                                   ; If no more ordinal operands follows.
        LODSD                                     ; EAX=pointer to the source text of the operand.
        MOV [%OrdPtr],EAX
        MOV EDX,EAX
        LODSD                                     ; Size of the text of the operand.
        MOV [%OrdSize],EAX
        MOV [%OrdBufPtr],ESI                      ; Prepare pointer for the next ordinal, if any.
        SUBD [%OrdBufSize],8
        TEST EAX
        JZ .10:                                   ; Skip an empty operand.
        Invoke ExpParseData::,EDI,EDX,EAX         ; Parse the source data EDX,EAX to expression EDI.
        JC .10:                                   ; Skip the operand if error was detected and reported.
        MOV EDX,[EDI+EXP.Status]                  ; DL='D', DH=datatype specified in ordinal operand ('B','W','S','I' etc) or 0.
        MOV EAX,[EBX+STM.Status]                  ; AL=datatype specified as D-mnemonic suffix.
        SHR EDX,8                                 ; DL=ordinal datatype.
        TEST DL
        JNZ .12:
        MOV DL,AL                                 ; Use D-mnemonic suffix if the ordinal specified a typeless data value, e.g. in DQ 3.14.
    .12:TEST AL
        JNZ .16:
    .14:MOV [EBX+STM.Status],DL                   ; Use 1st ordinal type as a default for all following typeless operands, if no Dsuffix, e.g. D "string",13,10.
        TEST DL
        JNZ .16:
        JNSt [EDI+EXP.Status],expString,.16:
        MOV DL,'U'                                ; String without datatype, e.g.  D "string". Its datatype is either 'B' or 'U'.
        JSt [Ea.Eaopt.Status::],eaoptUNICODE,.14:
        MOV DL,'B'
        JMP .14:
    .16:CMP DL,'S'
        JE .40:                                   ; If the ordinal defines a structured object, e.g. D 2*SomeStruc, goto .40:.
        ; Evaluate and emit ordinal nonstructured data from [%Ord] to [%DataEmitBuf],[%DataRelocBuf] (none of operands is a structured variable).
        ; Input: EBX=^STM, EDI=^EXP, DL=default datatype.
        Invoke StmCheckFields::,EBX,"?0*0"        ; Many ordinals but no keyword is permitted in nonstructured D.
        JC .74:
        BufferClear [%DataEmitBuf]
        BufferClear [%DataRelocBuf]
        Invoke ExpEvalData::,[%DataEmitBuf],[%DataRelocBuf],[%OrdPtr],[%OrdSize],EDX,EBX ; This might set Stm.Flags:stmtNotBSS.
        BufferRetrieve [%DataRelocBuf]            ; ESI,ECX contains zero or more RELOC records.
        JECXZ .20:
        ; One or more relocation appeared in this ordinal. Their origins must be patched
        ;     by the size of data emitted so far in this statement, and then stored to Stm.RelocBuffer.
    .18:PUSH ECX
          PUSH ESI
            BufferRetrieve [EBX+STM.EmitBuffer]   ; Get the size of emited data to ECX.
          POP ESI
          ADD [ESI+RELOC.OrgLow],ECX              ; Patch the relocation origin.
          BufferStore [EBX+STM.RelocBuffer],ESI,SIZE#RELOC ; Save the relocation ESI to the statement object.
        POP ECX
        ADD ESI,SIZE#RELOC
        SUB ECX,SIZE#RELOC
        JA .18:                                   ; If there are more relocations in this ordinal (duplicated data value was used).
    .20:BufferRetrieve [%DataEmitBuf]             ; Emitted or reserved data of this operand.
        BufferStore [EBX+STM.EmitBuffer],ESI,ECX  ; Save them to the statement.
        JMP .10:                                  ; The next ordinal operand of pseudoinstruction D.
    .22:; All operands are processed, now decide what kind of section (CODE, DATA or BSS)
        ;   should be actually used when AUTOSEGMENT=ON. This depends on Stm.Flags:stmtNotBSS flag.
        MOV EDI,[EBX+STM.Section]                 ; First assume that current section will not change.
        MOV ECX,sssPurposeCODE
        CMPB [EBX+STM.Status],'I'                 ; Data defined with pseudoinstruction DI go to a CODE section.
        JE .24:
        MOV ECX,sssPurposeDATA
        JSt [EBX+STM.Flags],stmtNotBSS,.24:       ; If some of the ordinals had initialized data value, it goes to DATA section.
        MOV ECX,sssPurposeBSS|sssPurposeSTACK     ; Otherwise all data are uninitialized. This will prefer BSS or STACK segment.
    .24:JSt [EBX+STM.CtxStatusAll],ctxSTRUC,.30:  ; Inside structure definition do not change section.
        TEST EDI
        JZ .26:                                   ; When no current section is specified, act as if AUTOSEGMENT=ON.
        JNSt [Ea.Eaopt.Status::],eaoptAUTOSEGMENT,.30: ; Do not change section when AUTOSEGMENT=OFF.
        JSt [EDI+SSS.Purpose],ECX,.30:            ; If the purpose of current section complies, do not change the section.
        ; AUTOSEGMENT=ON and the current section does not have the required purpose ECX. Let's switch to another section.
    .26:Invoke SssGetSegm::,[EBX+STM.Program],ECX ; Find a segment with purpose ECX.
        JNC .28:                                  ; If required section was found.
        RstSt ECX,sssPurposeSTACK                 ; If requested purpose was BSS|STACK, report only BSS.
        Invoke DictSearchByData::,DictSegmentPurpose::,ECX ; Returns purpose name Qword in ESI, to be used in error msg.
        Msg '3201',ESI                            ; No segment with PURPOSE=!1S found.
        MOV EAX,EDI
    .28:MOV EDI,EAX
    .30:MOV [EBX+STM.Section],EDI                 ; Data will be emitted|reserved in this section|structure EDI.
        TEST EDI
        JZ .66:
        JNSt [EBX+STM.Flags],stmtNotBSS,.32:
        SetSt [EDI+SSS.Status],sssNotBSS
    .32:JNSt [EDI+SSS.Status],sssSegment|sssSection,.34:
        SetSt [EDI+SSS.Status],sssUsed            ; Mark the section as dirty.
        Invoke SssCheckPurpose::,EDI,ECX          ; Warn if wrong section chosen (either auto or manually).
    .34:MOV EAX,[EDI+SSS.OrgLow]
        MOV EDX,[EDI+SSS.OrgHigh]
        JNSt [Ea.Eaopt.Status::],eaoptAUTOALIGN,.38:
        JSt [EBX+STM.CtxStatusAll],ctxSTRUC,.38:  ; Do not autoalign inside structure definition.
        ; Data will be autoaligned by the default datatype (by Dsuffix, otherwise by %1 datatype).
        PUSH EAX                                  ; Do not clobber section's offset in EDX:EAX.
          LEA ECX,[EBX+STM.Status]                ; ECX is a pointer to the suffix 'B','U','W'...
          Invoke DictLookup::,DictAlignValue::,ECX,1
          MOV ECX,0                               ; Prepare number of stuff bytes.
          JC .36:                                 ; No alignment found.
          Invoke ExpAlign::,[EDI+SSS.OrgLow],EAX,0 ; EAX is the required data alignment 1,2,4,8,16,32,64.
          MOV [EBX+STM.AlignBytes],ECX            ; ECX=Number of stuff bytes 0..63.
    .36:POP EAX
        ADD EAX,ECX
        ADC EDX,0
    .38:MOV [EBX+STM.OffsetLow],EAX               ; (AutoAligned) origin of this statement.
        MOV [EBX+STM.OffsetHigh],EDX
        JMP .66:                                  ; Continue at the epilogue code.
    .E6122:Msg PgmStatus=pgmLastPass,'6122',EAX   ; Structure "!1S" not found.
        JMP .50:                                  ; If not emitting an existing declared structure.
    .40:; Evaluate and emit structured data, e.g. Lbl DS 2*MyStructure, .Member1=Value1,.Member2=Value2".
        ; Input: EBX=^STM, EDI=^EXP, DL='S'.
        Invoke StmCheckFields::,EBX,"?01*"        ; Only one ordinal but many keywords are permitted in DS statement.
        MOV EAX,symDefined                        ; For the case of error E4810..E6840.
        JC .74:
        MOV EDX,[EBX+STM.Section]                 ; Current program section.
        BufferRetrieve [EBX+STM.OrdBuffer]
        MOV EAX,ECX                               ; Prepare !1S for E6122, e.g. MyStruc: DS ; No structure specified.
        JECXZ .E6122:                             ; Structure "!1S" not found.
        MOV EAX,ESI                               ; Pointer to 2*DWORD (ptr,size) of %1, i.e. name of the structure.
        MOV ESI,[EDI+EXP.Seg]                     ; ESI=^SSS structure, or 0 in pass1 if it's forward referenced.
        TEST ESI
        JZ .E6122:                                ; Structure "!1S" not found.
        JNSt [ESI+SSS.Status],sssNotBSS,.42:
        SetSt [EBX+STM.Flags],stmtNotBSS
    .42:SetSt [ESI+SSS.Status],sssUsed
        MOV EAX,[EBX+STM.Program]
        MOV ECX,[ESI+SSS.Purpose]
        MOV EDX,[EAX+PGM.CurrentSect]
        CMPD [EBX+STM.NrOfKeys],0                 ; Update some members of the structure with static data?
        JNA .44:                                  ; Skip if no member is statically initialized.
        SetSt [EBX+STM.Flags],stmtNotBSS          ; Some structure members are initialized with a keyword. e.g.DS aStruc, .Member=5.
        SetSt ECX,sssPurposeDATA                  ; At least one member is being updated,
        RstSt ECX,sssPurposeBSS                   ;  hence the structure should be emitted to data section.
    .44:JSt [EBX+STM.CtxStatusAll],ctxSTRUC,.50:  ; Do not change section inside STRUC/ENDSTRUC block.
        JNSt [Ea.Eaopt.Status::],eaoptAUTOSEGMENT,.50: ; Do not change section if AUTOSEGMENT=OFF.
        TEST EDX                                  ; Test if the current section is specified.
        JZ .46:
        JSt [EDX+SSS.Purpose],ECX,.50:            ; If the purpose of current section complies.
    .46:; Current section EDX does not have the required purpose ECX, try to switch to another section.
        Invoke SssGetSegm::,[EBX+STM.Program],ECX ; Returns pointer to a segment in EAX.
        JNC .48:                                  ; If segment autochanged successfully.
        Msg '3201',Dict_PurposeDATA::             ; No segment with PURPOSE=!1S found.
        MOV EAX,EDX                               ; Keep the current section in this case.
    .48:MOV EDX,EAX
    .50:MOV [EBX+STM.Section],EDX                 ; EDX=current or autoselected section where to emit data.
        TEST EDX
        JZ .66:
        MOV EDI,EDX                               ; EDX=EDI is section where the structured member will be emitted to.
        JNSt [EDI+SSS.Status],sssSegment|sssSection,.52:
        Invoke SssCheckPurpose::,EDI,ECX          ; Warn if wrong section purpose.
    .52:MOV EAX,[EDI+SSS.OrgLow]
        MOV EDX,[EDI+SSS.OrgHigh]
        JNSt [Ea.Eaopt.Status::],eaoptAUTOALIGN,.58: ; Skip if AUTOALIGN=OFF.
        ; Structured memory object specified with pseudoinstruction DS will be autoaligned
        ;   by the structure's own alignment, if it is already known.
        MOV ECX,[EDI+SSS.Alignment]               ; Structure of the object which is being defined.
        TEST ESI                                  ; ^SSS sssStructure.
        JZ .54:
        MOV ECX,[ESI+SSS.Alignment]               ; Structure which is being instanceized.
    .54:Invoke ExpAlign::,[EDI+SSS.OrgLow],ECX,0
        MOV [EBX+STM.AlignBytes],ECX              ; Number of stuff bytes.
        ADD EAX,ECX
        ADC EDX,0
    .58:MOV [EBX+STM.OffsetLow],EAX               ; AutoAligned origin of this statement.
        MOV [EBX+STM.OffsetHigh],EDX
        ; Structure contents will be duplicated to Stm.EmitBuffer.
        LEA EAX,[%DataExp]
        MOV EDX,[EAX+EXP.Seg]                     ; EDX=^SSS with emitting structure.
        ; Relocations specified in structure definition will be copied to Stm.RelocBuffer
        ;   and patched by the amount of so far emitted data in Stm.EmitBuffer, which is temporary kept in Stm.Size.
        CMPD [EAX+EXP.High],0                     ; Duplicator.
        JZ .66:                                   ; Emit nothing but symbol and autoalignment if zero duplicator, e.g. MyData DS 0*MyStruc.
    .60:; Otherwise emitted data in SSS.EmitBuffer will be updated by statement keywords and stored to Stm.
        ;   Entire structure emit-data will be copied to temporary [%DataEmitBuf]
        ;     and, if some statement keywords specified, corresponing member(s) will be rewritten.
        BufferClear [%StrucEmitBuf]
        BufferClear [%StrucRelocBuf]
        Invoke MemberUpdate::,EDX,EBX,[%StrucEmitBuf],[%StrucRelocBuf]
        BufferRetrieve [%StrucRelocBuf]
        JECXZ .64:
    .62:MOV EAX,[EBX+STM.Size]
        ADD [ESI+RELOC.OrgLow],EAX                ; Patch and store relocations from this duplication.
        ADCD [ESI+RELOC.OrgHigh],0
        BufferStore [EBX+STM.RelocBuffer],ESI,SIZE#RELOC
        ADD ESI,SIZE#RELOC
        SUB ECX,SIZE#RELOC
        JA .62:
    .64:BufferRetrieve [%StrucEmitBuf]
        ADD [EBX+STM.Size],ECX
        BufferStore [EBX+STM.EmitBuffer],ESI,ECX  ; Emit updated struc contents.
        LEA EAX,[%DataExp]
        DECD [EAX+EXP.High]                       ; Duplicator.
        JNZ .60:                                  ; Next duplication of the whole structure.
        JNSt [EBX+STM.Status],stmLabelPresent,.66:
        ; If label is present and duplicator nonzero, further duplications are ignored
        ;  and each member of the structure will create symbol in temporary struc expansion context.
        StackPush [Src.CtxStack::],0
        Invoke CtxCreate::,EAX,ctxSTRUC+ctxExpansion+ctxNamespace,EBX
        Invoke MemberCreate::,EDX,EBX
        StackPop [Src.CtxStack::]
    .66:; Common epilogue for structured and nonstructured data.
        BufferRetrieve [EBX+STM.EmitBuffer]
        MOV [EBX+STM.Size],ECX                    ; SIZE# attribute of statement's symbol, if defined.
        MOV EDX,[EBX+STM.Status]
        CMP DL,0
        MOV DL,'A'                                ; Operation D without data defaults to datatype 'A' (address).
        JNZ .68:
        MOV [EBX+STM.Status],EDX                  ; Attribute TYPE# of statement's symbol, if defined.
    .68:; Maintain sssNotBSS and structrure member when in structure definition.
        MOV ECX,[EBX+STM.Program]
        JECXZ .72:
        MOV EDI,[ECX+PGM.CurrentSect]
        TEST EDI
        JZ .72:
        JNSt [EDI+SSS.Status],sssStructure,.72:   ; If not inside a structure definition.
        MOVD [EDI+SSS.Purpose],sssPurposeBSS      ; Purpose of a structure reflects whether it declares static data or not.
        JNSt [EDI+SSS.Status],sssNotBSS,.70:
        MOVD [EDI+SSS.Purpose],sssPurposeDATA     ; Mark that the structure declaration has static data.
    .70:JNSt [EBX+STM.Status],stmLabelPresent,.80:
        LEA EAX,[%DataExp]
        MOV ECX,[EAX+EXP.Seg]
        Invoke MemberAdd::,EDI,EBX,ECX
    .72:; Define symbol if used in pseudoinstruction D.
        JNSt [EBX+STM.Status],stmLabelPresent,.80:
        MOV EAX,symDefined
        JNSt [EBX+STM.Status],stmLabelIsPublic,.74:
        OR EAX,symGlobalRef
    .74:Invoke SymCreate::,EAX,[EBX+STM.LabelPtr],[EBX+STM.LabelSize],EBX
    .80:Invoke EaBufferRelease::,[%DataEmitBuf]
        Invoke EaBufferRelease::,[%DataRelocBuf]
        Invoke EaBufferRelease::,[%StrucEmitBuf]
        Invoke EaBufferRelease::,[%StrucRelocBuf]
    .90:EndProcedure PseudoData

↑ PseudoD Stm
  Pseudoinstruction D handler.
Manual
  D
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  PseudoData
Tested by
  t2480

    PseudoD Procedure Stm
         MOV EBX,[%Stm]
         Invoke PseudoData,EBX
     .90:EndProcedure PseudoD

↑ PseudoDB Stm
  Pseudoinstruction DB handler.
Manual
  DB
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invokes
  PseudoData
Invoked from
  StmExecute
Tested by
  t2480

    PseudoDB Procedure Stm
         MOV EBX,[%Stm]
         MOVB [EBX+STM.Status],'B'
         Invoke PseudoData,EBX
        EndProcedure PseudoDB

↑ PseudoDU Stm
  Pseudoinstruction DU handler.
Manual
  DU
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  PseudoData
Tested by
  t2480

    PseudoDU Procedure Stm
         MOV EBX,[%Stm]
         MOVB [EBX+STM.Status],'U'
         Invoke PseudoData,EBX
        EndProcedure PseudoDU

↑ PseudoDW Stm
  Pseudoinstruction DW handler.
Manual
  DW
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  PseudoData
Tested by
  t2480

    PseudoDW Procedure Stm
         MOV EBX,[%Stm]
         MOVB [EBX+STM.Status],'W'
         Invoke PseudoData,EBX
        EndProcedure PseudoDW

↑ PseudoDD Stm
  Pseudoinstruction DD handler.
Manual
  DD
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  PseudoData
Tested by
  t2480

    PseudoDD Procedure Stm
         MOV EBX,[%Stm]
         MOVB [EBX+STM.Status],'D'
         Invoke PseudoData,EBX
        EndProcedure PseudoDD

↑ PseudoDQ Stm
  Pseudoinstruction DQ handler.
Manual
  DQ
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invokes
  PseudoData
Tested by
  t2480

    PseudoDQ Procedure Stm
         MOV EBX,[%Stm]
         MOVB [EBX+STM.Status],'Q'
         Invoke PseudoData,EBX
         EndProcedure PseudoDQ

↑ PseudoDT Stm
  Pseudoinstruction DT handler.
Manual
  DT
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  PseudoData

    PseudoDT Procedure Stm
         MOV EBX,[%Stm]
         MOVB [EBX+STM.Status],'T'
         Invoke PseudoData,EBX
        EndProcedure PseudoDT

↑ PseudoDO Stm
  Pseudoinstruction DO handler.
Manual
  DO
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  PseudoData

    PseudoDO Procedure Stm
         MOV EBX,[%Stm]
         MOVB [EBX+STM.Status],'O'
         Invoke PseudoData,EBX
        EndProcedure PseudoDO

↑ PseudoDY Stm
  Pseudoinstruction DY handler.
Manual
  DY
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  PseudoData

    PseudoDY Procedure Stm
         MOV EBX,[%Stm]
         MOVB [EBX+STM.Status],'Y'
         Invoke PseudoData,EBX
        EndProcedure PseudoDY

↑ PseudoDZ Stm
  Pseudoinstruction DZ handler.
Manual
  DZ
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  PseudoData

    PseudoDZ Procedure Stm
         MOV EBX,[%Stm]
         MOVB [EBX+STM.Status],'Z'
         Invoke PseudoData,EBX
        EndProcedure PseudoDZ

↑ PseudoDI Stm
  Pseudoinstruction DI handler.
Manual
  DI
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  PseudoData
Tested by
  t2510 t2515

    PseudoDI Procedure Stm
         MOV EBX,[%Stm]
         MOVB [EBX+STM.Status],'I'
         Invoke PseudoData,EBX
        EndProcedure PseudoDI

↑ PseudoDS Stm
  Pseudoinstruction DS handler.
Manual
  DS
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  PseudoData
Tested by
  t2500 t2510

    PseudoDS Procedure Stm
         MOV EBX,[%Stm]
         MOVB [EBX+STM.Status],'S'
         Invoke PseudoData,EBX
        EndProcedure PseudoDS

↑ PseudoENDHEAD Stm
  Pseudoinstruction ENDHEAD handler.
Manual
  ENDHEAD
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invokes
  StmCheckFields
Tested by
  t1230

    PseudoENDHEAD Procedure Stm
         MOV EBX,[%Stm]
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90:
         StmInStruc EBX,.90: ; Do not allow this statement in a structure definition.
         Invoke StmCheckFields::, EBX,"00?0"
    .90:EndProcedure PseudoENDHEAD

↑ PseudoEUROASM Stm
  Pseudoinstruction EUROASM handler.
Manual
  EUROASM
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  DictLookup EaoptAssemble StmCheckFields
Tested by
  t2210 t2220 t2291

    PseudoEUROASM Procedure Stm
          MOV EBX,[%Stm]
          JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.99:
          Invoke StmCheckFields::,EBX,'00**'
          SetSt [Src.Lst.Status::],lstNoData
          ; EUROASM statement may have ordinal operands PUSH and POP.
          BufferRetrieve [EBX+STM.OrdBuffer]
          LEA EDX,[ESI+ECX]
     .10: CMP ESI,EDX
          JNB .30: ; If no more ordinals.
          LODSD ; Ordinal operand.
          MOV EDI,EAX
          LODSD
          MOV ECX,EAX
          Invoke DictLookup::, DictEuroasmOrd::, EDI,ECX
          JNC .20:
          LEA EAX,[ESI-8]
          Msg cc=C,'7810',EAX,DictEuroasmOrd:: ;Unknown EUROASM ordinal "!1S". Expected one of !2L.
          JMP .10:
    .20:  JMP EAX ; .PUSH or .POP.
    .PUSH::StackPush [Src.EaoptStack::], Ea.Eaopt::
          JMP .10:
    .POP::StackPop [Src.EaoptStack::]
          Msg cc=C,'3812' ; EUROASM POP without EUROASM PUSH. Ignored.
          JC .10:
          CopyTo Ea.Eaopt::,EAX,Size=SIZE#EAOPT
          JMP .10:
    .30:  ; Handle all EUROASM keyword operands.
          BufferRetrieve [EBX+STM.KeyBuffer]
          LEA EDX,[ESI+ECX]
    .40:  CMP ESI,EDX
          JNB .99: ; If no more keywords.
          Invoke EaoptAssemble::, Ea.Eaopt::, [ESI+0],[ESI+4],[ESI+8],[ESI+12]
          ADD ESI,16
          JMP .40:
    .99: EndProcedure PseudoEUROASM

↑ PseudoHEAD Stm
  Pseudoinstruction HEAD handler.
Manual
  HEAD
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  StmCheckFields
Tested by
  t1230

    PseudoHEAD Procedure Stm
         MOV EBX,[%Stm]
         StmInStruc EBX,.90: ; Do not allow this statement in a structure definition.
         SetSt [Src.Lst.Status::],lstNoData
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90:
         Invoke StmCheckFields::, EBX,"*000"
    .90:EndProcedure PseudoHEAD

↑ PseudoNoOperation Stm
  PseudoNoOperation is handler for statements which have unrecognized or none operation field. They may have label and/or prefix(es) only.
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invokes
  SssCreateSe SssFindByName SssGetSegm SssGuessPurpose StmCheckFields SymCreate
Invoked by
  StmExecute

    PseudoNoOperation Procedure Stm
         MOV EBX,[%Stm]
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90:
         JNSt [EBX+STM.Status],stmLabelPresent|stmPrefixPresent|stmOperationPresent,.90: ; Skip empty statement.
         MOV EDI,[EBX+STM.Program]
         TEST EDI
         JZ .90:
         MOV EAX,[EDI+PGM.CurrentSect]
         TEST EAX
         JZ .10:
         MOV [EBX+STM.Section],EAX
    .10: JNSt [EBX+STM.Status],stmLabelPresent, .50:
         MOV ESI,[EBX+STM.LabelPtr]
         CMPB [ESI],'['
         JNE .50:
         ; The statement is [new_section_definition] or [existing_section_switch], e.g.[NewSect].
         StmInStruc EBX,.90:                         ; Do not allow this statement in a structure definition.
         Invoke StmCheckFields::,EBX,"1000"
         JC .90:
         MOV ECX,[EBX+STM.LabelSize]
         CMPB [ESI+ECX-1],']'
         JE .20:
    .E7831:Msg '7831',EBX                            ; Segment or section name "!1S" must be in braces [].
         JMP .90:
    .20: INC ESI
         SUB ECX,2                                   ; Strip [].
         StripSpaces ESI,ECX
         TEST ECX
         JZ .E7831:                                  ; Segment or section name "!1S" must be in braces [].
         RstSt [Ea.Eaopt.Status::],eaoptAUTOSEGMENT  ; AUTOSEGMENT is silently switched OFF by any statement which changes section.
         Invoke SssFindByName::,sssSection|sssSegment,0,ESI,ECX,0
         JNC .40:                                    ; Skip when an old section is being switched to.
         ; New section ESI,ECX is being declared in current segment.
         MOV EAX,[EBX+STM.Section]                   ; Previous section.
         TEST EAX
         JZ .30:
         MOV EAX,[EAX+SSS.SegmPtr]                   ; Get curent segment.
         TEST EAX
         JZ .30:
         MOV EDX,[EAX+SSS.Status]                    ; Parent segment status.
         AND EDX,sssWidthMask+sssCombineMask+sssNotBSS ; New section inherits those properties.
         OR EDX,sssSection+sssDefinedInPass
         Invoke SssCreateSe::,EBX,EAX,ESI,ECX,EDX,[EAX+SSS.Purpose],[EAX+SSS.Alignment] ; Returns pointer to the new section in EAX.
         RstSt [EAX+SSS.Purpose],sssPurposeLITERAL   ; This purpose is not inherited.
         JMP .40:
    .30: ; No previous segment was specified, let's create a new segment+section with the name ESI,ECX.
         MOV EDX,pgmoptWidthMask
         AND EDX,[EDI+PGM.Pgmopt.Status]             ; Inherit segment width from program width.
         SetSt EDX,sssSegment+sssSection+sssPublic+sssDefinedInPass
         Invoke SssCreateSe::,EBX,0,ESI,ECX,EDX,0,16
         Invoke SssGuessPurpose::,EAX
         JNZ .40:
         SetSt [EAX+SSS.Purpose],sssPurposeRegular
    .40: MOV [EBX+STM.Section],EAX                   ; Switch to section EAX.
         MOV [EDI+PGM.CurrentSect],EAX
         SetSt [Src.Lst.Status::],lstSectInline      ; Display [NewSect] in dump column on the same line of listing.
         JNSt [EBX+STM.Status],stmOperationPresent,.90:
         LEA ECX,[EBX+STM.OperationPtr]
         Msg '6860',ECX                              ; Unrecognized operation "!1S", ignored.
         JMP .90:
    .50: ; Label is missing or it is not in [], e.g.: Unknown.
         JNSt [EBX+STM.Status],stmOperationPresent,.55:
         LEA ECX,[EBX+STM.OperationPtr]
         Msg '6860',ECX                              ; Unrecognized operation "!1S", ignored.
         JMPS .60:
    .55:; Statement EBX may have  label/prefix but it is not [section] switch. E.g.Label:LOCK.
         Invoke StmCheckFields::,EBX,"**00"
         JC .90:
    .60: MOVB [EBX+STM.Status],'A'
         MOV EDX,[EDI+PGM.CurrentSect]
         TEST EDX
         JNZ .65:
         Invoke SssGetSegm::,EDI, sssPurposeCODE
         MOV EDX,EAX
    .65: MOV ECX,[EBX+STM.NrOfPrefixes]
         MOV [EBX+STM.Size],ECX
         JECXZ .80:
         SetSt [EBX+STM.Flags],stmtNotBSS
         ; The statement has machine prefix(es)..
         MOVB [EBX+STM.Status],'I'
         StmInStruc EBX,.90:                         ; Do not allow this statement in a structure definition.
         LEA ESI,[EBX+STM.Prefix1Data]
     .70:BufferStore [EBX+STM.EmitBuffer],ESI,1
         ADD ESI,STM.Prefix2Data-STM.Prefix1Data
         LOOP .70:
         JNSt [Ea.Eaopt.Status::],eaoptAUTOSEGMENT, .80:
         MOV EDX,[EDI+PGM.CurrentSect]
         TEST EDX
         JZ .75:
         JSt [EDX+SSS.Purpose],sssPurposeCODE,.80:
    .75: Invoke SssGetSegm::, EDI, sssPurposeCODE    ; Find the first code section to swich to when AUTOSEGMENT=ON.
         JC .80:
         MOV EDX,EAX
    .80: MOV [EBX+STM.Section],EDX
         MOV ESI,EDX
         TEST ESI
         JZ .90:
         MOV EAX,[ESI+SSS.OrgLow]                    ; Update statement offset when section changed.
         MOV EDX,[ESI+SSS.OrgHigh]
         MOV [EBX+STM.OffsetLow],EAX
         MOV [EBX+STM.OffsetHigh],EDX
         JNSt [EBX+STM.Status],stmLabelPresent,.90:
         ; The statement has a label.
         MOV EAX,stmLabelIsPublic
         AND EAX,[EBX+STM.Status]
         OR  EAX,symDefined
         Invoke SymCreate::,EAX,[EBX+STM.LabelPtr],[EBX+STM.LabelSize],EBX
    .90:EndProcedure PseudoNoOperation

↑ PseudopcCOMMENT Stm
  Pseudoinstruction %COMMENT handler.
Manual
  %COMMENT
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxCreate StmCheckFields

    PseudopcCOMMENT Procedure Stm
         MOV EBX,[%Stm]
         SetSt [Src.Lst.Status::],lstNoData
         MOV ECX,[EBX+STM.CtxStatusAll]
         AND ECX,ctxNoEmit
         JNZ .50:
         Invoke StmCheckFields::,EBX,"?000"
     .50:StackPush [Src.CtxStack::],0
         OR  ECX,ctxCOMMENT+ctxNoEmit
         Invoke CtxCreate::,EAX,ECX,EBX
     .90:EndProcedure PseudopcCOMMENT

↑ PseudopcENDCOMMENT Stm
  Pseudoinstruction %ENDCOMMENT handler.
Manual
  %ENDCOMMENT
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invokes
  CtxDiscard CtxFind StmCheckFields

    PseudopcENDCOMMENT Procedure Stm
         MOV EBX,[%Stm]
         SetSt [Src.Lst.Status::],lstNoData
         Invoke CtxFind::,ctxCOMMENT,EBX
         Msg cc=C,'7120',Dict_PseudopcENDCOMMENT:: ; Wrong nesting, unexpected !1S.
         JC .90:
         Msg cc=NE,'7110',Dict_PseudopcENDCOMMENT::,EAX ; Wrong nesting, expected "!1S !2S".
     .50:Invoke StmCheckFields::,EBX,"00?0"
         Invoke CtxDiscard::,EAX,EBX
     .90:EndProcedure PseudopcENDCOMMENT

↑ PseudopcDISPLAY Stm
  Pseudoinstruction %DISPLAY handler.
Manual
  %DISPLAY
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  EaBufferRelease EaBufferReserve StmCheckFields
Tested by
  t2520 t2904 t2907 t2910 t2913

    PseudopcDISPLAY Procedure Stm
    ContBuf LocalVar ; Buffer for contents of expanded %variable.
    SortBuf LocalVar ; Buffer contains pointers to object name. Used for aplhabetical sort.
    StrBuf  LocalVar ; Buffer contains Qwords(ptr,size) with object name.
    NameBuf LocalVar ; Buffer contains concatenated % and formal name of variables.
    PgmPtr  LocalVar ; Cached pointer to the current PGM object.
    ParA    LocalVar ; Temporary storage for Msg parameters.
    ParB    LocalVar ; Temporary storage for Msg parameters.
    ParC    LocalVar ; Temporary storage for Msg parameters.
    ParD    LocalVar ; Temporary storage for Msg parameters.
    ParR    LocalVar Size=24 ; File range, such as "{1234567890..1234567890}"
    ParQN   LocalVar Size=8  ; Qword(ptr,size) with raw key name.
    ParQV   LocalVar Size=8  ; Qword(ptr,size) with raw key value.
    MaskQV  LocalVar Size=8  ; Qword(ptr,size) with normalized key value (filterring mask).
    ParVal  LocalVar Size=24 ; Room for parameter conversion to a decimal number.
    VarName LocalVar Size=32 ; Maximal length of any Pgmopt/Eaopt/SysVar name used in €ASM is 32.
         MOV EBX,[%Stm]
         Invoke StmCheckFields::,EBX,"00**"
         JC .99:
         ; Initialization of %DISPLAY engine.
         SetSt [Src.Lst.Status::],lstNoData
         Invoke EaBufferReserve::,PseudopcDISPLAY
         MOV [%ContBuf],EAX
         Invoke EaBufferReserve::,PseudopcDISPLAY
         MOV [%SortBuf],EAX
         Invoke EaBufferReserve::,PseudopcDISPLAY
         MOV [%StrBuf],EAX
         Invoke EaBufferReserve::,PseudopcDISPLAY
         MOV [%NameBuf],EAX
         MOV EAX,[EBX+STM.Program]
         MOV [%PgmPtr],EAX
      ; Processing %DISPLAY ordinal operands.
         LEA ECX,[%MaskQV]
         XOR EAX,EAX
         MOV [ECX+0],EAX                             ; Ordinal %DISPLAY operands have no filterring mask.
         MOV [ECX+4],EAX
         MOV ECX,[EBX+STM.NrOfOrdinals]
         JECXZ .20:
         BufferRetrieve [EBX+STM.OrdBuffer]
         MOV ECX,[EBX+STM.NrOfOrdinals]
    .10: MOV EDI,ESI                                 ; EDI points to Qword(ptr,size) of ordinal operand.
         SUB EDX,EDX
         PUSH EBX,ECX,ESI
          CALL .Operand                              ; EDI=^Qword(ptr,size) with %DISPLAY key, EDX=0 (no filter).
         POP ESI,ECX,EBX
         ADD ESI,8
         LOOP .10:
    .20:; Processing %DISPLAY keyword operands. It may specify a mask, e.g. %DISPLAY Sym=Sys*
         BufferRetrieve [EBX+STM.KeyBuffer]
         MOV ECX,[EBX+STM.NrOfKeys]
         JECXZ .40:
    .30: MOV EDI,ESI                                 ; EDI points to Oword(nameptr,namesize,valueptr,valuesize) od keyword operand.
         LEA EDX,[ESI+8]
         PUSH ECX,ESI
          CALL .Operand                              ; EDI=^Qword with %DISPLAY key, EDX=^Qword with raw filter value.
         POP ESI,ECX
         ADD ESI,16
         LOOP .30:
    .40: Msg '1790' ; **** End of %%DISPLAY
         Invoke EaBufferRelease::,[%NameBuf]
         Invoke EaBufferRelease::,[%StrBuf]
         Invoke EaBufferRelease::,[%SortBuf]
         Invoke EaBufferRelease::,[%ContBuf]
    .99:EndProcedure PseudopcDISPLAY

    ; %DISPLAY handlers will emit one debug message for each €ASM object.
    ; Input: EDI=^QW (ptr,size) with key category name (e.g. "Literals")
    ;        EBX=[%PgmPtr].
    ;        [%MaskQV]=^QW(ptr,size) with normalized filter value, perhaps empty.
    ; Output:Handlers may destroy any GPR but EBP.

    PseudopcDISPLAY.ALL::PROC                                       ; Display all €ASM objects.
          LEA EDX,[%MaskQV]
          Msg '1100',EDX ; **** %%DISPLAY All=!1S*
          CALL PseudopcDISPLAY.FILES
          CALL PseudopcDISPLAY.CHUNKS
          CALL PseudopcDISPLAY.SEGMENTS
          CALL PseudopcDISPLAY.STRUCTURES
          CALL PseudopcDISPLAY.CONTEXT
          CALL PseudopcDISPLAY.SYMBOLS
          CALL PseudopcDISPLAY.LITERALSYMBOLS
          CALL PseudopcDISPLAY.RELOCATIONS
          CALL PseudopcDISPLAY.MACROS
          CALL PseudopcDISPLAY.VARIABLES
          RET
          ENDP PseudopcDISPLAY.ALL::

    PseudopcDISPLAY.FILES:: PROC                                    ; Display the name, property and contents of each source/configuration  file.
         Msg '1150'                                  ; **** %%DISPLAY Files
         MOV ESI,Src.IniFile::                       ; Local configuration file.
         MOV EDX,=B"config"
         JSt [ESI+FILE.Status],fileStFound,.F1:
         MOV EDX,=B"not found"
    .F1: LEA EDI,[ESI+FILE.Name]
         PUSH ESI
          MOV ESI,EDI
          CALL PseudopcDISPLAY.ForwardSlash:
         POP ESI
         Msg '1160',EDI,[ESI+FILE.Size],EDX          ; "!1$",size=!2K,src=!3$.
         MOV ESI,Ea.SrcFile::                        ; Main source file.
         LEA EDI,[ESI+FILE.Name]
         PUSH ESI
          MOV ESI,EDI
          CALL PseudopcDISPLAY.ForwardSlash:
         POP ESI
         Msg '1170',EDI,[ESI+FILE.Size]              ; "!1$",size=!2K,src=main source
         SUB ECX,ECX                                 ; Included files counter.
    .F3: CMP ECX,[EBX+PGM.InclFilesNr]
         JNB .F9:
         MOV ESI,[EBX+PGM.InclLinePtrTable]
         MOV EDI,[EBX+PGM.InclFilesTable]
         MOV EDX,[ESI+4*ECX]                         ; EDX=LinePtr
         MOV ESI,[EDI+4*ECX]                         ; ESI=^FILE.
         LEA EAX,[ESI+FILE.Name]
         PUSH EAX,ESI
          MOV ESI,EAX
          CALL PseudopcDISPLAY.ForwardSlash:
         POP ESI,EAX
         Msg '1180',EAX,[ESI+FILE.Size],EDX          ; "!1$",size=!2K,src=included in !3@.
         INC ECX
         JMP .F3:
    .F9: RET
         ENDP PseudopcDISPLAY.FILES::

    PseudopcDISPLAY.ForwardSlash: PROC ; Convert backslash from ASCIIZ string at ESI to forward slash.
           PUSH EAX,ESI,EDI
            MOV EDI,ESI
    .S2:    LODSB
            CMP AL,0
            JE .S8:
            CMP AL,'\'
            JNE .S5:
            MOV AL,'/'
    .S5:    STOSB
            JMP .S2:
    .S8:   POP EDI,ESI,EAX
           RET
         ENDP PseudopcDISPLAY.ForwardSlash:

    PseudopcDISPLAY.CHUNKS:: PROC
        Msg '1200'                                   ; **** %%DISPLAY Chunks of source text.
        ListGetFirst [Src.ChunkList::]
        JZ .I9:
    .I0:MOV EBX,[EAX+CHUNK.FilePtr]
        SUB ESI,ESI
        MOV [%ParA],ESI
        TEST EBX
        JZ .I1:
        CALL .ChunkRange
        LEA ESI,[EBX+FILE.Name]
        CALL PseudopcDISPLAY.ForwardSlash:
    .I1:LEA EBX,[%ParQN]
        MOV EDI,[EAX+CHUNK.Bottom]
        MOV EDX,[EAX+CHUNK.Top]
        SUB EDX,EDI
        MOV ECX,EDX
        StripSpaces EDI,EDX                          ; Display only non-white chunk contents.
        PUSHAD
          ADD EDX,EDI
          DEC EDI
    .I2:  INC EDI
          CMP EDI,EDX
          JNB .I4:
          CMPB [EDI],'\'
          JNE .I2:
    .     MOVB [EDI],'/'
          JMP .I2:
    .I4:POPAD
        MOV [EBX+0],EDI
        MOV [EBX+4],EDX
        JNSt [EAX+CHUNK.Status],chunkError,.I6:
        LEA EDI,[%ParVal]
        MOV EDX,[EAX+CHUNK.Status]
        SHR EDX,16                                   ; DX is now binary Msg identifier.
        PUSH EAX,EDI
          MOV AL,'W'
          CMP DX,5000
          JB .I5:
          MOV AL,'E'
    .I5:  STOSB
          MOV EAX,EDX
          StoD EDI,Size=4,Align=right,LeadingZeroes=yes
          XOR EAX,EAX
          STOSB
        POP EDI,EAX
        JMP .I7:
    .I6:MOV EDI,=B"orig"
        JSt [EAX+CHUNK.Status],chunkOrig|chunkOrigBin,.I7:
        MOV EDI,=B"binary"
        JSt [EAX+CHUNK.Status],chunkBin,.I7:
        MOV EDI,=B"source"
        JNSt [EAX+CHUNK.Status],chunkResolved|chunkSkipped,.I7:
        MOV EDI,=B"resolved"
        JNSt [EAX+CHUNK.Status],chunkSkipped,.I7:
        MOV EDI,=B"skipped"
    .I7:MOV EDX,=B"included"
        JSt [EAX+CHUNK.Status],chunkIncluded,.I8:
        MOV EDX,=B"envelope"
        JSt [EAX+CHUNK.Status],chunkEnvelope,.I8:
        MOV EDX,=B"main"
    .I8:Msg '1210',ESI,[%ParA],EDX,EDI,ECX,EBX       ; !"!1$"!2S,src=!3$,type=!4$,size=!5D,contents=''!6S''
        ListGetNext EAX
        JNZ .I0:
    .I9:RET
      ENDP PseudopcDISPLAY.CHUNKS::

    PseudopcDISPLAY.CHUNKS.ChunkRange PROC ; Create chunk range within the file contents as sublist operation.
    ; Input: EAX=^CHUNK, EBX=^FILE.
    ; Output: %ParR= sublist operator which describes the chunk, e.g. "{12..23}"
    ;         %ParQV= Dword(ptr,size) of the sublist operator in %ParR.
    ;         %ParA= ^ParQV (Msg parameter !2S).  ECX,EDX,ESI,EDI undefined.
        PUSH EAX
         MOV EDI,[EBX+FILE.BufPtr]
         MOV ECX,[EAX+CHUNK.Bottom]
         MOV EAX,[EBX+FILE.BufSize]
         SUB EDX,EDX ; Line counter.
         ADD EAX,EDI ; BufTop.
         CMP ECX,EAX
         JNB .90:                                    ; If chunk EAX is not from file EBX, leave %ParA=0.
         SUB ECX,EDI
         JB .90:                                     ; If chunk EAX is not from file EBX, leave %ParA=0.
         ; Examine left range value.
         MOV AL,10
         INC EDX                                     ; Line numbers start from 1.
     .20:JECXZ .30:
         REPNE SCASB
         JNE .20:
         INC EDX
         JMP .20:
     .30:LEA EDI,[%ParR]
         MOV AL,'{'
         STOSB
         XCHG EAX,EDX
         MOV [%ParC],EAX                             ; Temporary store left range value.
         StoD EDI
         MOV [%ParB],EDI                             ; Temporary save ptr to future range operator .. into ParR.
        POP EAX
        ; Examine right range value.
        PUSH EAX
         MOV EDI,[EBX+FILE.BufPtr]
         MOV ECX,[EAX+CHUNK.Top]
         SUB EDX,EDX ; Line counter.
         SUB ECX,EDI
         MOV AL,10
         INC EDX                                     ; Line numbers start from 1.
     .40:JECXZ .50:
         REPNE SCASB
         JNE .40:
         INC EDX
         JMP .40:
     .50:CMP [EDI-1],AL
         JNE .60:
         DEC EDX
     .60:MOV EDI,[%ParB]
         CMP EDX,[%ParC]
         JBE .80:                                    ; If left and right range values are equal or if range is empty.
         MOV AL,'.'
         STOSB                                       ; Range operator.
         STOSB
         XCHG EAX,EDX
         StoD EDI                                    ; Right range value.
     .80:MOV AL,'}'
         STOSB
         LEA ESI,[%ParR]
         SUB EDI,ESI
         LEA EAX,[%ParQV]
         MOV [%ParA],EAX
         MOV [EAX+0],ESI
         MOV [EAX+4],EDI
    .90:POP EAX
        RET
       ENDP PseudopcDISPLAY.CHUNKS.ChunkRange

    PseudopcDISPLAY.GROUPS::
    PseudopcDISPLAY.SECTIONS::
    PseudopcDISPLAY.SEGMENTS:: PROC
         Msg '1250'                                  ; **** %%DISPLAY groups, segments and sections.
         MOV EBX,[%PgmPtr]
         TEST EBX
         JZ .Se9:
         ListGetFirst [EBX+PGM.SssList]
         JZ .Se9:
    .Se1:JNSt [EAX+SSS.Status],sssGroup,.Se3:
         CALL .Gr:                                   ; %Display group EAX and its segments.
    .Se3:ListGetNext EAX
         JNZ .Se1:

         ListGetFirst [EBX+PGM.SssList]              ; %Display groupless segments.
    .Se5:JNSt [EAX+SSS.Status],sssSegment,.Se8:
         CMPD [EAX+SSS.GroupPtr],0
         JNZ .Se8:                                   ; If segment EAX belongs to a group, it was already displayed.
         CALL .Sg:                                   ; %Display groupless segment EAX and its sections.
    .Se8:ListGetNext EAX
         JNZ .Se5:
    .Se9:RET

    .Gr: PUSHAD                                      ; %Display group EAX and its segments.
         MOV EDX,EAX
         BufferClear [%NameBuf]
         BufferClear [%SortBuf]
         ListGetFirst [EBX+PGM.SssList]
    .Gr1:JNSt [EAX+SSS.Status],sssSegment,.Gr2:
         CMP [EAX+SSS.GroupPtr],EDX
         JNE .Gr2:
         PUSH EAX
          MOV EAX,ESP
          BufferStore [%SortBuf],EAX,4
         POP EAX
    .Gr2:ListGetNext EAX
         JNZ .Gr1:
         BufferRetrieve [%SortBuf]
         SAR ECX,2
         JZ .Gr5:
    .Gr3:LODSD
         BufferStore [%NameBuf],=B' [',2
         BufferStore [%NameBuf],[EAX+0],[EAX+4]
         BufferStore [%NameBuf],=B']',1
         LOOP .Gr3:
    .Gr5:BufferRetrieve [%NameBuf]
         PUSH ECX,ESI
           MOV ECX,ESP
           Msg '1260',EDX,ECX,[EDX+SSS.LinePtr]      ; [!1S],group!2S,src=!3@
         POP ESI,ECX
         ListGetFirst [EBX+PGM.SssList]
    .Gr6:JNSt [EAX+SSS.Status],sssSegment,.Gr8:
         CMP [EAX+SSS.GroupPtr],EDX
         JNE .Gr8:
         CALL .Sg:                                   ; %Display segment EAX and its sections.
    .Gr8:ListGetNext EAX
         JNZ .Gr6:
         POPAD
         RET

    .Sg: PUSHAD                                      ; %Display segment EAX and its sections.
         BufferClear [%SortBuf]
         BufferClear [%NameBuf]
         Invoke SssPurposeToText::,[EAX+SSS.Purpose],[%NameBuf]
         BufferRetrieve [%NameBuf]
         MOV [%ParA],ESI
         MOV EBX,sssWidthMask
         MOV EDX,[EAX+SSS.Status]
         AND EBX,EDX
         SAR EBX,20
         MOV [%ParB],EBX
         MOV EBX,[EAX+SSS.Alignment]
         MOV [%ParC],EBX
         MOV EBX,sssCombineMask
         AND EBX,EDX
         Invoke DictSearchByData::, DictSegmentCombine::,EBX
         LEA ECX,[EAX+SSS.ClassPtr]
         Msg '1270',EAX,[%ParA],[%ParB],[%ParC],ESI,ECX,[EAX+SSS.LinePtr] ; [!1S],purpose=!2$,width=!3D,align=!4K,combine=!5S,class="!6S",source=!7@
         ; Now display all sections which belong to segment EAX. The first section is always identical with segment EAX.
         MOV EDX,[%PgmPtr]
         MOV EBX,EAX
         ListGetFirst [EDX+PGM.SssList]
    .Sg3:JNSt [EAX+SSS.Status],sssSection, .Sg6:
         CMP EBX,[EAX+SSS.SegmPtr]
         JNE .Sg6:                                   ; If not our segment's section.
         PUSH EAX
          MOV EAX,ESP
          BufferStore [%SortBuf],EAX,4               ; Store pointer to section.
         POP EAX
    .Sg6:ListGetNext EAX
         JNZ .Sg3:
         BufferRetrieve [%SortBuf]                   ; Sections will be displayed in SECTION# order, i.e. by bottom offset.
         SAR ECX,2
         JZ .Sg9:
         ShellSort ESI,ECX,4, .CmpSssBottom
         BufferRetrieve [%SortBuf]
         SAR ECX,2
    .Sg7:LODSD
         MOV EDX,[EAX+SSS.TopLow]
         MOV EBX,[EAX+SSS.Alignment]
         SUB EDX,[EAX+SSS.BottomLow]
         PUSH ECX
          MOV CX,"YN"
          JSt [EAX+SSS.Status],sssUsed,.Sg8:
          XCHG CL,CH
     .Sg8:Msg '1280',EAX,[EAX+SSS.BottomLow],EDX,EBX,ECX,[EAX+SSS.LinePtr] ; !1S],address=!2Hh,size=!3Hh=!3K,align=!4D,ref=!5Z,src=!6@
         POP ECX
         LOOP .Sg7:
    .Sg9:POPAD
         RET
        ENDP PseudopcDISPLAY.SEGMENTS::

    PseudopcDISPLAY.SEGMENTS.CmpSssBottom PROC                               ; Callback to compare two sections pointed to with [ESI] and [EDI] by .Bottom.
         PUSH EBX                                    ; ShellSort requires to keep EBX,ECX unchanged.
          MOV EDX,[EDI]
          MOV EBX,[ESI]
          MOV EAX,[EDX+SSS.BottomLow]
          CMP EAX,[EBX+SSS.BottomLow]
          JAE .90:                                   ; If the order is ascending.
          MOV [ESI],EDX                              ; Otherwise swap both pointers and set CF.
          MOV [EDI],EBX
          STC
     .90:POP EBX
         RET
         ENDP PseudopcDISPLAY.SEGMENTS.CmpSssBottom

    PseudopcDISPLAY.STRUCTURES::PROC
         LEA EDX,[%MaskQV]
         Msg '1300',EDX                              ; **** %%DISPLAY Structures=!1S*
         BufferClear [%SortBuf]
         MOV EBX,[%PgmPtr]
         TEST EBX
         JZ .St9
         ListGetFirst [EBX+PGM.SssList]
         JZ .St9:
    .St2:JNSt [EAX+SSS.Status],sssStructure, .St8:
         CALL PseudopcDISPLAY.PutObj
    .St8:ListGetNext EAX
         JNZ .St2:
         Invoke EaBufferSort::,[%SortBuf]
         BufferRetrieve [%SortBuf]
         SAR ECX,2
         JZ .St9: ; If empty buffer.
    .DS1:LODSD
         PUSH ECX,ESI
           BufferClear [%NameBuf]
           Invoke SssPurposeToText::,[EAX+SSS.Purpose],[%NameBuf]
           BufferRetrieve [%NameBuf]
           MOV [%ParA],ESI
           MOV ECX,[EAX+SSS.Status]
           MOV BX,"YN"
           JSt ECX,sssUsed,.DS5:
           XCHG BL,BH
    .DS5:  MOV ECX,[EAX+SSS.Alignment]
                     ; !1S,size=!2K,align=!3K,purpose=!4$,ref=!5Z,source=!6@
           Msg '1310',EAX,[EAX+SSS.TopLow],ECX,[%ParA],EBX,[EAX+SSS.LinePtr]
         POP ESI,ECX
         LOOP .DS1:
    .St9:RET
       ENDP PseudopcDISPLAY.STRUCTURES::

    PseudopcDISPLAY.CONTEXT:: PROC
          Msg '1350'                                 ; **** %%DISPLAY Context
          MOV EDI,[Src.CtxStack]
          TEST EDI
          JZ .Ctx9:
          MOV EBX,[EDI+STACK.Bottom]
    .Ctx1:CMP EBX,[EDI+STACK.Ptr]
          JNB .Ctx9:
          MOV EAX,[EBX+CTX.Status]                   ; EBX=context  EDI=Src.CtxStack
          MOV ESI,Dict_PseudoPROGRAM::
          JSt EAX,ctxPROGRAM,.Ctx3:
          MOV ESI,Dict_PseudoHEAD::
          JSt EAX,ctxHEAD,.Ctx3:
          MOV ESI,Dict_PseudoPROC::
          JSt EAX,ctxPROC,.Ctx3:
          MOV ESI,Dict_PseudoPROC1::
          JSt EAX,ctxPROC1,.Ctx3:
          MOV ESI,Dict_PseudoSTRUC::
          JSt EAX,ctxSTRUC,.Ctx3:
          MOV ESI,Dict_PseudopcMACRO::
          JSt EAX,ctxMACRO,.Ctx3:
          MOV ESI,Dict_PseudopcFOR::
          JSt EAX,ctxFOR,.Ctx3:
          MOV ESI,Dict_PseudopcWHILE::
          JSt EAX,ctxWHILE,.Ctx3:
          MOV ESI,Dict_PseudopcREPEAT::
          JSt EAX,ctxREPEAT,.Ctx3:
          MOV ESI,Dict_PseudopcIF::
          JSt EAX,ctxIF,.Ctx3:
          MOV ESI,Dict_PseudopcCOMMENT::
          JSt EAX,ctxCOMMENT,.Ctx3:
          SUB ESI,ESI
    .Ctx3:MOV EDX,=B"envelope"
          JNSt EAX,ctxPROGRAM,.Ctx4:
          MOV ECX,[EBX+CTX.ObjPtr]
          JECXZ .Ctx4:
          JSt [ECX+PGM.Status],pgmEnvelope,.Ctx5:
    .Ctx4:MOV EDX,=B"main"
    .Ctx5:AND EAX,ctxNoEmit
          MOV AX,"YN"
          JZ .Ctx6:
          XCHG AL,AH
    .Ctx6:Msg '1360',EBX,ESI,EDX,EAX,[EBX+CTX.ExpansionNr] ; !1S !2S,src=!3$,emit=!4Z,%%.=!5D
          ADD EBX,SIZE#CTX
          JMP .Ctx1:
    .Ctx9: RET
         ENDP PseudopcDISPLAY.CONTEXT::

    PseudopcDISPLAY.DisplaySym PROC                                 ; Common procedure to display all symbols whose pointers are in [%SortBuf].
         Invoke EaBufferReserve::,PseudopcDISPLAY.DisplaySym
         MOV [%ParB],EAX
         Invoke EaBufferSort::,[%SortBuf]            ; Order displayed symbols alphabetically.
         BufferRetrieve [%SortBuf]
         SAR ECX,2
         JZ .DS9:                                    ; If empty buffer.
    .DS1:LODSD                                       ; EAX is now pointer to the displayed symbol.
         PUSH EBX,ECX,ESI                            ; Prepare Msg parameters !7Z,!8Z,!6$ to BL,CL,DL.
           MOV BX,"YN"
           JSt [EAX+SYM.Status],symFixed,.DS4:
           XCHG BL,BH
    .DS4:  MOV CX,"YN"
           JSt [EAX+SYM.Status],symReferenced,.DS5:
           XCHG CL,CH
    .DS5:  MOV DL,'X'
           JSt [EAX+SYM.Status],symExport, .DS6:
           MOV DL,'I'
           JSt [EAX+SYM.Status],symImport, .DS6:
           MOV DL,'P'
           JSt [EAX+SYM.Status],symPublic, .DS6:
           MOV DL,'E'
           JSt [EAX+SYM.Status],symExtern, .DS6:
           MOV DL,'G'
           JSt [EAX+SYM.Status],symGlobal|symGlobalRef, .DS6:
           MOV DL,'S'
    .DS6:  BufferClear [%ParB]
           MOV DH,"'"
           BufferStoreWord [%ParB],EDX
           CMPD [EAX+SYM.DllNameSize],0
           JZ .DS8:
           JSt [EAX+SYM.Status],symDefined,.DS8:     ; Do not display lib= when public symbol is exported.
           BufferStoreDword [%ParB],',lib'
           BufferStoreWord  [%ParB],'="'
           BufferStore      [%ParB],[EAX+SYM.DllNamePtr],[EAX+SYM.DllNameSize]
    .DS7:  BufferStoreByte  [%ParB],'"'
    .DS8:  BufferStoreByte  [%ParB],0
           PUSH ECX
             BufferRetrieve   [%ParB]
           POP ECX
           Msg '1450',EAX,[EAX+SYM.Section],[EAX+SYM.OffsetLow],[EAX+SYM.Status], \
                      [EAX+SYM.Size],ESI,ECX,EBX,[EAX+SYM.LinePtr]
           ; !1S,[!2S]:!3Hh,type=''!4Z'',size=!5K,scope=''!6$,ref=''!7Z'',fix=!8Z,source=!9@
         POP ESI,ECX,EBX
         DEC ECX
         JNZ .DS1:
    .DS9:Invoke EaBufferRelease::,[%ParB]
         RET
        ENDP PseudopcDISPLAY.DisplaySym

    PseudopcDISPLAY.SYMBOLS:: PROC                                  ; Display all non-literal symbols (fixed, unfixed, referenced, unreferenced).
         LEA EDX,[%MaskQV]
         Msg '1400',EDX                              ; **** %%DISPLAY Symbols=!1S*
          BufferClear [%SortBuf]
          MOV EBX,[%PgmPtr]
          TEST EBX
          JZ .Su9:
          ListGetFirst [EBX+PGM.SymList]
          JZ .Su9:
    .Su2: JSt [EAX+SYM.Status],symLiteral, .Su8:
          CALL PseudopcDISPLAY.PutObj
    .Su8: ListGetNext EAX
          JNZ .Su2:
          CALL PseudopcDISPLAY.DisplaySym
    .Su9: RET
        ENDP PseudopcDISPLAY.SYMBOLS::

    PseudopcDISPLAY.UNFIXEDSYMBOLS::PROC
          LEA EDX,[%MaskQV]
          Msg '1410',EDX                             ; **** %%DISPLAY UnfixedSymbols=!1S*
          BufferClear [%SortBuf]
          MOV EBX,[%PgmPtr]
          TEST EBX
          JZ .Su9:
          ListGetFirst [EBX+PGM.SymList]
          JZ .Su9:
    .Su2:;;;;;;;;;;; JSt [EAX+SYM.Status],symLiteral, .Su8:
          JSt [EAX+SYM.Status],symFixed, .Su8:
          CALL PseudopcDISPLAY.PutObj
    .Su8: ListGetNext EAX
          JNZ .Su2:
          CALL PseudopcDISPLAY.DisplaySym
    .Su9: RET
          ENDP PseudopcDISPLAY.UNFIXEDSYMBOLS::

    PseudopcDISPLAY.FIXEDSYMBOLS::PROC
          LEA EDX,[%MaskQV]
          Msg '1420',EDX                             ; **** %%DISPLAY FixedSymbols=!1S*
          BufferClear [%SortBuf]
          MOV EBX,[%PgmPtr]
          TEST EBX
          JZ .Sr9:
          ListGetFirst [EBX+PGM.SymList]
          JZ .Sr9:
    .Sr2: JSt  [EAX+SYM.Status],symLiteral,.Sr8:
          JNSt [EAX+SYM.Status],symFixed, .Sr8:
          CALL PseudopcDISPLAY.PutObj
    .Sr8: ListGetNext EAX
          JNZ .Sr2:
          CALL PseudopcDISPLAY.DisplaySym
    .Sr9: RET
         ENDP PseudopcDISPLAY.FIXEDSYMBOLS::

    PseudopcDISPLAY.UNREFERENCEDSYMBOLS::PROC
          LEA EDX,[%MaskQV]
          Msg '1430',EDX                             ; **** %%DISPLAY UnreferencedSymbols=!1S*
          BufferClear [%SortBuf]
          MOV EBX,[%PgmPtr]
          TEST EBX
          JZ .Su9:
          ListGetFirst [EBX+PGM.SymList]
          JZ .Su9:
    .Su2: ;;;;;;;;JSt [EAX+SYM.Status],symLiteral, .Su8:
          JSt [EAX+SYM.Status],symUsed, .Su8:
          CALL PseudopcDISPLAY.PutObj
    .Su8: ListGetNext EAX
          JNZ .Su2:
          CALL PseudopcDISPLAY.DisplaySym
    .Su9: RET
          ENDP PseudopcDISPLAY.UNREFERENCEDSYMBOLS::

    PseudopcDISPLAY.REFERENCEDSYMBOLS::PROC
          LEA EDX,[%MaskQV]
          Msg '1440',EDX                             ; **** %%DISPLAY ReferencedSymbols=!1S*
          BufferClear [%SortBuf]
          MOV EBX,[%PgmPtr]
          TEST EBX
          JZ .Sr9:
          ListGetFirst [EBX+PGM.SymList]
          JZ .Sr9:
    .Sr2: JSt  [EAX+SYM.Status],symLiteral,.Sr8:
          JNSt [EAX+SYM.Status],symUsed, .Sr8:
          CALL PseudopcDISPLAY.PutObj
    .Sr8: ListGetNext EAX
          JNZ .Sr2:
          CALL PseudopcDISPLAY.DisplaySym
    .Sr9: RET
         ENDP PseudopcDISPLAY.REFERENCEDSYMBOLS::

    PseudopcDISPLAY.LITERALSYMBOLS::PROC
          LEA EDX,[%MaskQV]
          Msg '1500',EDX                             ; **** %%DISPLAY LiteralSymbols=!1S*
          BufferClear [%SortBuf]
          MOV EBX,[%PgmPtr]
          TEST EBX
          JZ .Sl9:
          ListGetFirst [EBX+PGM.SymList]
          JZ .Sl9:
    .Sl2: JNSt [EAX+SYM.Status],symLiteral, .Sl8:
          CALL PseudopcDISPLAY.PutObj
    .Sl8: ListGetNext EAX
          JNZ .Sl2:
          CALL PseudopcDISPLAY.DisplaySym
    .Sl9: RET
          ENDP PseudopcDISPLAY.LITERALSYMBOLS::

    PseudopcDISPLAY.RELOCATIONS:: PROC
         Msg '1550'                                  ; **** %%DISPLAY relocations
         ListGetFirst [EBX+PGM.SssList]
         JZ .RL9:
    .RL2:MOV [%ParA],EAX                             ; ^SSS.
         BufferRetrieve [EAX+SSS.EmitBuffer]
         MOV [%ParB],ESI
         ADD ECX,ESI
         MOV [%ParC],ECX                             ; Emited contents is between [%ParB]..[%ParC].
         BufferRetrieve [EAX+SSS.RelocBuffer]
         JECXZ .RL8:
         ADD ECX,ESI
         MOV [%ParD],ECX
    .RL3:CALL .RelocESI:                             ; Display one RELOC ESI.
         ADD ESI,SIZE# RELOC
         CMP ESI,[%ParD]
         JB .RL3:                                    ; The next RELOC.
    .RL8:ListGetNext [%ParA]                         ; The next segment.
         JNZ .RL2:
    .RL9:RET
        ENDP PseudopcDISPLAY.RELOCATIONS::

    PseudopcDISPLAY.RELOCATIONS.RelocESI: PROC                                  ; Display one relocation at ESI.
    ;                                 EBX                EDI
    ; 1560 at=[!1S]:!2Hh,width=16,obj=!3Wh,add=!4Wh,type=!5$,tg=!6S,[!7S]:!8Hh
    ; 1570 at=[!1S]:!2Hh,width=32,obj=!3Hh,add=!4Hh,type=!5$,tg=!6S,[!7S]:!8Hh
    ; 1580 at=[!1S]:!2Hh,width=64,obj=!3Qh,add=!4Qh,type=!5$,tg=!6S,[!7S]:!8Hh
          MOV EDX,[ESI+RELOC.Status]
          JSt EDX,relocIgnore,.RE9:
          XOR EBX,EBX                                ; EBX will be the value of relocated object in emitted contents (or pointer if 64).
          MOV EDI,[ESI+RELOC.OrgLow]
          MOV ECX,[ESI+RELOC.Section]
          SUB EDI,[ECX+SSS.BottomLow]
          ADD EDI,[%ParB]                            ; Let EDI point to the relocated object.
          INC EDI,EDI
          CMP EDI,[%ParC]
          JNB .RE1:
          DEC EDI,EDI
          MOV EBX,EDI
          JSt EDX,relocWidth64,.RE1:
          MOV EBX,[EDI]
    .RE1: MOV EDI,=B"abs"                            ; EDI will be the relocation type.
          JSt EDX,relocAbsVA,.RE3:
          MOV EDI,=B"rel"
          JSt EDX,relocRel,.RE3:
          MOV EDI,=B"absRVA"
          JSt EDX,relocAbsRVA,.RE3:
          MOV EDI,=B"para"
          JSt EDX,relocPara,.RE3:
          MOV EDI,=B"far"
          JSt EDX,relocFar,.RE3:
          MOV EDI,=B"?"
    .RE3: MOV ECX,[ESI+RELOC.Symbol]
          XOR EAX,EAX
          XOR EDX,EDX
          JECXZ .RE5:
          MOV EAX,[ECX+SYM.Section]
          MOV EDX,[ECX+SYM.OffsetLow]
    .RE5: JNSt [ESI+RELOC.Status],relocWidth32,.RE6:
          Msg '1570',[ESI+RELOC.Section],[ESI+RELOC.OrgLow],EBX,[ESI+RELOC.AddendLow],EDI,ECX,EAX,EDX
          RET
    .RE6: JNSt [ESI+RELOC.Status],relocWidth64,.RE7:
          PUSH EBP
           LEA EBP,[ESI+RELOC.AddendLow]
           Msg '1580',[ESI+RELOC.Section],[ESI+RELOC.OrgLow],EBX,EBP,EDI,ECX,EAX,EDX
          POP EBP
          RET
    .RE7: Msg '1560',[ESI+RELOC.Section],[ESI+RELOC.OrgLow],EBX,[ESI+RELOC.AddendLow],EDI,ECX,EAX,EDX
    .RE9: RET
         ENDP PseudopcDISPLAY.RELOCATIONS.RelocESI:

    PseudopcDISPLAY.MACROS:: PROC
         LEA EDX,[%MaskQV]
         Msg '1600',EDX ; **** %%DISPLAY Macros=!1S*
         BufferClear [%SortBuf]
         MOVD [%ParA],0
     .M1:Invoke CtxPeek::, ctxPROGRAM, [%ParA]
         JC .M5:
         MOV [%ParA],EAX ; PROGRAM context.
         MOV EBX,[EAX+CTX.ObjPtr]
         TEST EBX
         JZ .M1:
         MOV ECX,[EBX+PGM.PassPtr]
         JECXZ .M1:
         ListGetFirst [ECX+PASS.MacList]
         JZ .M1:
     .M2:CALL PseudopcDISPLAY.PutObj
         ListGetNext EAX
         JNZ .M2:
         JMP .M1:
     .M5:Invoke EaBufferSort::,[%SortBuf]
         BufferRetrieve [%SortBuf]
         SAR ECX,2
         JZ .M9:
     .M7:LODSD
         MOV EBX,=B'default'
         JNSt [EAX+MAC.Status],macLabeled,.M8:
         MOV EBX,=B'%%:'
     .M8:Msg '1610',EAX,EBX,[EAX+MAC.LinePtr]     ; !1S,entry=!2$,source=!3@
         LOOP .M7:
     .M9:RET
       ENDP PseudopcDISPLAY.MACROS::

    PseudopcDISPLAY.DisplayVar PROC ; Common procedure for display (as message D1770/D1780)
      ; preprocessing %variables whose pointers are stored in %SortBuf.
      ; Input: EDX=0 only if system %^variables are presented. Nonzero in automatic, formal and user-defined %variables.
           Invoke EaBufferSort::,[%SortBuf]
           BufferRetrieve [%SortBuf]
           SAR ECX,2
           JZ .DV9: ; If empty buffer.
    .DV1:  BufferClear [%ContBuf] ; Temporary buffer for %variable contents.
           LODSD ; EAX is now ^VAR.
           TEST EDX
           JNZ .DV4: ; Use D1770 if formal or user-defined %variable is displayed.
           MOV EDI,'1780' ; Volatile system variables %^DATE,%^TIME,%^TIMESTAMP,%^EUROASMOS,%^VERSION
           ; are presented with MsgId='1780' instead of '1770' in order to allow suppressing with NOWARN=1780 in tests.
           MOV EBX,[EAX+0]
           MOV EBX,[EBX+2] ; Skip the first two characters %^ of system variable name.
           CMP EBX,"TIME"
           JE .DV5:
           CMP EBX,"DATE"
           JE .DV5:
           CMP EBX,"EURO"
           JE .DV5:
           CMP EBX,"VERS"
           JE .DV5:
    .DV4:  MOV EDI,'1770' ; Default MsgId.
    .DV5:  MOV EBX,[EAX+4] ; Variable name size, including the leading percent sign.
           ADD EBX,[EAX+0]
           Invoke VarExpand::,[EAX+0],EBX,[%ContBuf],-1 ; Get %variable contents into %ContBuf.
           JC .DV8:
           MOV EAX,[ESI-4] ; Restore pointer to VAR.
           PUSH ECX,ESI
             BufferRetrieve [%ContBuf]
             PUSH ECX,ESI ; Size,Ptr to %variable contents.
               MOV EBX,ESP ; EBX=Qword(Ptr,size) with %variable contents.
               Msg EDI,EAX,EBX,ECX ; !1S=!2S, size=!3D.
             POP ESI,ECX
           POP ESI,ECX ; Restore pointer in %SortBuf contents.
    .DV8:  LOOP .DV1: ; Display the next %variable.
    .DV9:  RET
          ENDP PseudopcDISPLAY.DisplayVar

    PseudopcDISPLAY.VARIABLES::PROC
         LEA EDX,[%MaskQV]
         Msg '1700',EDX ; **** %%DISPLAY Variables=%%!1S*
         CALL PseudopcDISPLAY.AUTOMATICVARIABLES
         CALL PseudopcDISPLAY.FORMALVARIABLES
         CALL PseudopcDISPLAY.USERVARIABLES
         CALL PseudopcDISPLAY.SYSTEMVARIABLES
         RET
         ENDP PseudopcDISPLAY.VARIABLES::

    PseudopcDISPLAY.AUTOMATICVARIABLES:: PROC
          Msg '1710' ; **** %%DISPLAY AutomaticVariables. No filter applies.
          Invoke CtxPeek::, ctxMACRO,0
          JC .Va9:  ; If not in macro context.
          MOV EBX,EAX
          JNSt [EBX+CTX.Status],ctxExpansion,.Va9: ; Skip if in macro definition.
          BufferRetrieve [EBX+CTX.ObjBuffer]
          CMP ECX,SIZE#CTX_MAC
          JNE .Va0: ; This should never happen.
      ; varTypeLabel %:
          LEA EDI,[ESI+CTX_MAC.LabelPtr]
          Msg '1720',=B':',EDI,[EDI+4] ; name="%%!1$",value="!2S",size=!3D'
          ; varTypeOrd %0,%1,%2,,,
          LEA EDI,[ESI+CTX_MAC.MacroNamePtr] ; Macro name %0.
          Msg '1730',0,EDI,[EDI+4] ; name="%%!1D",value="!2S",size=!3D
          BufferRetrieve [EBX+CTX.OrdBuffer] ; 2*DDs keeping values of ordinal operands.
          JECXZ .Va3:
          LEA EAX,[ESI+ECX] ; EAX=end of ordinal Qwords.
    .Va0: MOVD [%ParA],1 ; ParA keep ordinal number.
    .Va1: MOV ECX,[EBX+CTX.Shift]
          ADD ECX,[%ParA]
          JNG .Va2: ; If shifted out below zero.
          LEA EDI,[ESI+8*ECX-8]
          CMP EDI,EAX
          JNB .Va3: ; If the last ordinal displayed.
          Msg '1730',[%ParA],EDI,[EDI+4] ; name="%%!1D",value="!2S",size=!3D
    .Va2: INCD [%ParA] ; The next ordinal.
          JMP .Va1:
    .Va3:
      ; varTypeOrdLen %#
          BufferRetrieve [EBX+CTX.OrdBuffer] ; Qword(ptr,size) keeping values of ordinal operands.
          SAR ECX,3
          LEA EDI,[%ParVal]
          MOV EAX,ECX
          MOV ECX,EDI
          StoD EDI
          SUB EDI,ECX
          LEA EAX,[%ParQV]
          MOV [EAX+0],ECX
          MOV [EAX+4],EDI
          Msg '1720',=B'#',EAX,EDI ; name="%%!1$",value="!2S",size=!3D
     ; varTypeOrdList %*
          Invoke EaBufferReserve::,PseudopcDISPLAY.AUTOMATICVARIABLES
          MOV EDI,EAX ; Temporary buffer for concatenation of ordinals.
          BufferRetrieve [EBX+CTX.OrdBuffer]
          JECXZ .Va5:
    .Va4: BufferStore EDI,[ESI+0],[ESI+4]
          ADD ESI,8
          SUB ECX,8
          JNA .Va5:
          BufferStore EDI,=B',',1
          JMP .Va4:
    .Va5: BufferRetrieve EDI
          LEA EAX,[%ParQV]
          MOV [EAX+0],ESI
          MOV [EAX+4],ECX
          Msg '1720',=B'*',EAX,ECX ; %%!1$=!2S, size=!3D
          Invoke EaBufferRelease::,EDI
     ; varTypeKeyLen %=#
          BufferRetrieve [EBX+CTX.KeyBuffer]
          SAR ECX,4
          LEA EDI,[%ParVal]
          MOV EAX,ECX ; Number of used keywords.
          MOV ECX,EDI
          StoD EDI
          SUB EDI,ECX
          LEA EAX,[%ParQV]
          MOV [EAX+0],ECX
          MOV [EAX+4],EDI
          Msg '1720',=B'=#',EAX,EDI ; name="%%!1$",value="!2S",size=!3D
     ; varTypeKeyList %*
          Invoke EaBufferReserve::,PseudopcDISPLAY.AUTOMATICVARIABLES
          MOV EDI,EAX ; Temporary buffer for concatenation of keywords.
          BufferRetrieve [EBX+CTX.KeyBuffer]
          JECXZ .Va7:
    .Va6: BufferStore EDI,[ESI+0],[ESI+4]
          BufferStore EDI,=B'=',1
          BufferStore EDI,[ESI+8],[ESI+12]
          ADD ESI,16
          SUB ECX,16
          JNA .Va7:
          BufferStore EDI,=B',',1
          JMP .Va6:
    .Va7: BufferRetrieve EDI
          LEA EAX,[%ParQV]
          MOV [EAX+0],ESI
          MOV [EAX+4],ECX
          Msg '1720',=B'=*',EAX,ECX ; %%!1$=!2S, size=!3D
          Invoke EaBufferRelease::,EDI
    .Va9: RET
         ENDP PseudopcDISPLAY.AUTOMATICVARIABLES::

    PseudopcDISPLAY.FORMALVARIABLES:: PROC
    .VF:: LEA EDX,[%MaskQV]
          Msg '1740',EDX ; **** %%DISPLAY FormalVariables=%%!1S*
          BufferClear [%SortBuf]
          BufferClear [%StrBuf]
          BufferClear [%NameBuf]
          SUB EAX,EAX
     .Vf1:Invoke CtxPeek::, ctxMACRO | ctxFOR, EAX
          JC .Vf9: ; If no more macro/for context.
          BufferRetrieve [EAX+CTX.FrmBuffer]
          JC .Vf5:
          JECXZ .Vf5:
     .Vf3: ; ESI,ECX is one or more formal parameters (NamePtr,NameSize,ValPtr,ValSize). NameSize may be 0.
          PUSH EAX,ECX,ESI
            MOV ECX,[ESI+4] ; [ESI],ECX is now formal %variable name size without percent sign.
            JECXZ .Vf4:
            BufferNew [%StrBuf],8 ; Room for Ptr/Size.
            MOV EDI,EAX
            BufferNew [%NameBuf],1 ; Room for % prefix.
            MOV [EDI+0],EAX ; Ptr to %.
            MOVB [EAX],'%%'
            MOV ESI,[ESI+0] ; Pointer to formal name without %.
            BufferStore [%NameBuf],ESI,ECX
            INC ECX
            MOV [EDI+4],ECX ; Size of formal %variable name.
            MOV EAX,EDI
            CALL PseudopcDISPLAY.PutObj
     .Vf4:POP ESI,ECX,EAX
          ADD ESI,16
          SUB ECX,16
          JG .Vf3:
     .Vf5:JMP .Vf1: ; Search for further context from EAX.
     .Vf9: ; Formal %variables are displayed, EDX<>0.
          CALL PseudopcDISPLAY.DisplayVar
          RET
         ENDP PseudopcDISPLAY.FORMALVARIABLES::

    PseudopcDISPLAY.USERVARIABLES:: PROC
          LEA EDX,[%MaskQV]
          Msg '1750',EDX ; **** %%DISPLAY UserVariables=%%!1S*
          BufferClear [%SortBuf]
          MOVD [%ParA],0 ; Program context marker.
    .Vu1: Invoke CtxPeek::, ctxPROGRAM, [%ParA]
          JC .Vu9:
          MOV [%ParA],EAX ; PROGRAM context.
          MOV EBX,[EAX+CTX.ObjPtr]
          TEST EBX ; Does the context specify a program?
          JZ .Vu1: ; If not, try the parent program context.
          MOV ECX,[EBX+PGM.PassPtr]
          JECXZ .Vu1:
          ListGetFirst [ECX+PASS.VarList]
          JZ .Vu1:
    .Vu2: CALL PseudopcDISPLAY.PutObj
          ListGetNext EAX
          JNZ .Vu2: ; Find the next %variable.
          JMP .Vu1: ; Find the parent program context.
    .Vu9: ; User-defined %variables are displayed, EDX<>0.
          CALL PseudopcDISPLAY.DisplayVar
          RET
          ENDP PseudopcDISPLAY.USERVARIABLES::

    PseudopcDISPLAY.SYSTEMVARIABLES::PROC
          LEA EDX,[%MaskQV]
          Msg '1760',EDX ; **** %%DISPLAY SystemVariables=%%!1S*
          ; Convert mask to uppercase in situ.
          MOV ESI,[EDX+0] ; MaskPtr.
          MOV ECX,[EDX+4] ; MaskSize.
          JECXZ .Vs4:
    .Vs1: LODSB
          CMP AL,'a'
          JB .Vs3:
          CMP AL,'z'
          JA .Vs3:
          AND AL,~('a'^'A') ; Convert AL to uppercase.
          MOV [ESI-1],AL
    .Vs3: LOOP .Vs1:
    .Vs4: BufferClear [%SortBuf]
          BufferClear [%StrBuf]
          BufferClear [%NameBuf]
          MOV EAX,DictPgmopt::
    .Vsp: MOV ECX,[EAX+DICT.Size]
          JECXZ .VsEM: ; If Dict End reached in dictionary table.
          CALL PseudopcDISPLAY.PutObjAsSysVar
          ADD EAX,SIZE#DICT
          JMP .Vsp:
    .VsEM:MOV EAX,DictEaoptMisc::
    .VseM:MOV ECX,[EAX+DICT.Size]
          JECXZ .VsES: ; If Dict End reached in dictionary table.
          CALL PseudopcDISPLAY.PutObjAsSysVar
          ADD EAX,SIZE#DICT
          JMP .VseM:
    .VsES:MOV EAX,DictEaoptStatus::
    .VseS:MOV ECX,[EAX+DICT.Size]
          JECXZ .VsEF: ; If Dict End reached in dictionary table.
          CALL PseudopcDISPLAY.PutObjAsSysVar
          ADD EAX,SIZE#DICT
          JMP .VseS:
    .VsEF:MOV EAX,DictEaoptFea::
    .VseF:MOV ECX,[EAX+DICT.Size]
          JECXZ .VsS: ; If Dict End reached in dictionary table.
          CALL PseudopcDISPLAY.PutObjAsSysVar
          ADD EAX,SIZE#DICT
          JMP .VseF:
    .VsS: MOV EAX,DictEasmSysVar::
    .Vss: MOV ECX,[EAX+DICT.Size]
          JECXZ .VsD: ; If Dict End reached in dictionary table.
          CALL PseudopcDISPLAY.PutObjAsSysVar
          ADD EAX,SIZE#DICT
          JMP .Vss:
    .VsD: XOR EDX,EDX ; Signalize that system %^variables are displayed.
          CALL PseudopcDISPLAY.DisplayVar
          RET
          ENDP PseudopcDISPLAY.SYSTEMVARIABLES::

    PseudopcDISPLAY.PutObj PROC ; Common procedure for filterring and putting pointer to an object
    ; from EAX to [%SortBuf]. Object is SYM/SSS/VAR/MAC/DICT or anything starting with NamePtr/NameSize Qword.
    ; This PROC is used to gather object to [%SortBuf] before their sort and display.
    ; Input: EAX=pointer to object.
    ;        EDX=pointer to QWORD (Ptr/Size) to filter.
    ;            The filter is normalized (no leading %^ or trailing *), it may be empty.
    ;            The filter is converted to uppercase in case of system %^variables.
    ; Output:ECX,ESI,EDI destroyed.
    ;        Pointer to the object which passed the filter is added to [%SortBuf].
         MOV ESI,[EAX+0] ; Object name ptr.
         MOV ECX,[EAX+4] ; Object name size.
      ;;;   ;LEA EDX,[%MaskQV]
         JECXZ .Skip: ; If the object has no name, do not display.
         MOV EDI,[EDX+4] ; Normalized filtering mask size.
         TEST EDI
         JZ .Put: ; If empty filter specified, display the object.
         CMPB [ESI],'%%' ; Normalize object name (remove leading % or %^) just for filterring purpose.
         JNE .po5:
         INC ESI ; If object name begins with %, skip the percent sign.
         DEC ECX
         JZ .Skip:
         CMPB [ESI],'^' ; If object name begins with %^, skip those characters.
         JNE .po5:
         INC ESI
         DEC ECX
    .po5:CMP ECX,EDI
         JB .Skip: ; If the object name is shorter than filter, do not display.
         MOV ECX,EDI ; Compare only the number of characters in filter value.
         MOV EDI,[EDX+0] ; Filtering mask pointer.
         REPE CMPSB
         JNE .Skip: ; If name of object does not match the filter.
    .Put:PUSH EAX
          MOV EAX,ESP
          BufferStore [%SortBuf],EAX,4 ; Store pointer to the object with unnormalized name.
         POP EAX
    .Skip:RET
        ENDP PseudopcDISPLAY.PutObj

    PseudopcDISPLAY.PutObjAsSysVar PROC ; Similar to .PutObj but object type is VAR and its name is prefixed with %^.
    ; Input: EAX=pointer to object.
    ;        EDX=pointer to QWORD (Ptr/Size) to uppercased filter.
    ;            The filter is normalized (no leading %^ or trailing *), it may be empty.
    ; Output:ECX,ESI,EDI destroyed.
    ;        Pointer to the object which passed the filter is added to [%SortBuf].
         PUSH EAX
          MOV ESI,EAX ; ^object DICT.
          BufferNew [%StrBuf],8; Make room for Ptr/Size.
          MOV EDI,EAX ; ^Qword.
          BufferNew [%NameBuf],2 ; Make room for %^ prefix.
          MOV [EDI+0],EAX ; Ptr to future %^.
          MOVW [EAX],'%%^'
          MOV ECX,[ESI+4] ; Object name size.
          MOV ESI,[ESI+0] ; Pointer to object name without %.
          BufferStore [%NameBuf],ESI,ECX ; Store object name right behind %^.
          INC ECX
          INC ECX
          MOV [EDI+4],ECX ; Size of system %^variable name.
          MOV EAX,EDI
          CALL PseudopcDISPLAY.PutObj
         POP EAX
         RET
        ENDP PseudopcDISPLAY.PutObjAsSysVar

    PseudopcDISPLAY.Operand PROC ; Processing one operand (ordinal or keyword) of %DISPLAY statement.
         ; Input: EDI=^QW(Ptr,Size) with %DISPLAY key as specified by user.
         ;        EDX=0 or ^QW(Ptr,Size) with raw filter value as specified by user.
         ; Output: any GPR but EBP may be destroyed.
         LEA ESI,[%MaskQV]                           ; Prepare mask for the case of empty filter (EDX=0).
         XOR EAX,EAX
         MOV [ESI+0],EAX
         MOV [ESI+4],EAX
         TEST EDX
         JZ .80:                                     ; If no filter.
         ; Raw filter value EDX will be normalized and put to [%MaskQV]:
         ;     leading % or %^ removed, trailing * removed.
         MOV ESI,[EDX+0]
         MOV ECX,[EDX+4]
         StripSpaces ESI,ECX
         JECXZ .80:                                  ; If empty filter.
         CMPB [ESI+ECX-1],'*'
         JNE .20:
         DEC ECX                                     ; Remove the trailing * from filter value.
     .20:JECXZ .80:                                  ; If empty filter (nothing but *).
         CMPB [ESI],'%%'
         JNE .70:
         INC ESI                                     ; Remove the leading % from filter value.
         DEC ECX
         JECXZ .80:                                  ; If empty filter (nothing but %*).
         CMPB [ESI],'^'
         JNE .70:
         INC ESI                                     ; Remove the leading %^ from filter value.
         DEC ECX
     .70:StripSpaces ESI,ECX
         LEA EDX,[%MaskQV]
         MOV [EDX+0],ESI
         MOV [EDX+4],ECX                             ; [%MaskQV] now has nonempty normalized filter value.
     .80:Invoke DictLookupObj::, [EDI+0],[EDI+4]     ; Find the %DISPLAY category by (incomplete) key name.
         Msg cc=C,'3751',EDI,DictDisplayObj::        ; Invalid %%DISPLAY option "!1S". Expected !2L
         JC .90:
         MOV EBX,[%PgmPtr]
         CALL EAX                                    ; Perform the %DISPLAY handler.
    .90: RET
         ENDP PseudopcDISPLAY.Operand

↑ PseudopcFOR Stm
  Pseudoinstruction %FOR handler. It opens %FOR/%ENDFOR block. On the 1st occurence in a pass it will push ctxFOR, initialize CTX_FOR object stored in the context and assign formal %variable with the first value.
  Corresponding PseudopcENDFOR will assign next value to formal %variable, if any, and continue assembly behind %FOR statement. Otherwise it pops ctxFOR.
Manual
  %FOR
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  Ctx1stRepeat CtxCreate CtxExpansionNrUpdate CtxForNext DictLookup ExpEvalNum LstSet StmCheckFields
Tested by
  t2640 t2641 t2642

    PseudopcFOR Procedure Stm
    ForPassPool LocalVar
         MOV EBX,[%Stm]
         MOV EAX,[EBX+STM.Program]
         TEST EAX
         JZ .90:
         MOV ECX,[EAX+PGM.PassPtr]
         TEST ECX
         JZ .90:
         MOV EAX,[ECX+PASS.Pool]
         TEST EAX
         JZ .90:
         MOV [%ForPassPool],EAX
         JNSt [EBX+STM.CtxStatusAll],ctxNoEmit,.20:
         ; %FOR in NoEmit will only push ctxFOR+ctxNoEmit.
         StackPush [Src.CtxStack::],0
         MOV EDI,EAX
         Invoke Ctx1stRepeat:: ;Returns EAX=ctx1stRepeat only if all repeating contexts have it too.
         MOV ECX,ctxFOR+ctxRepeat+ctxNoEmit
         OR ECX,EAX
         Invoke CtxCreate::,EDI,ECX,EBX
         JMP .90:
     .20:; %FOR statement. We might get here either in normal stm flow or from corresponding %ENDFOR statement.
         StackPeekLast [Src.CtxStack::]
         JC .90:
         MOV EDI,EAX
         JNSt [EAX+CTX.Status],ctxFOR,.30:
         MOV EAX,[EDI+CTX.LinePtr]
         CMP EAX,[EBX+STM.LinePtr]
         JE .80: ; We came here from %ENDFOR, prepare the next formal %variable.
     .30:; New %FOR block encounterred in emitting status. Push ctxFOR context.
         Invoke StmCheckFields::,EBX,"10*?"
         JC .90:
         StackPush [Src.CtxStack::],0
         MOV EDI,EAX ; New created context.
         Invoke Ctx1stRepeat:: ;Returns EAX=ctx1stRepeat only if all repeating contexts have it too.
         MOV ECX,ctxFOR+ctxExpansion+ctxExpandable+ctxFormal+ctxRepeat+ctxStep0
         OR ECX,EAX
         Invoke CtxCreate::,EDI,ECX,EBX
         BufferNew [EDI+CTX.ObjBuffer],SIZE#CTX_FOR
         MOV [EDI+CTX.ObjPtr],EAX
         MOV ECX,[EBX+STM.NrOfOrdinals]
         MOV EBX,EAX ; EBX now points to the new uninitialized CTX_FOR object.
         SUB EAX,EAX
         MOV [EBX+CTX_FOR.NrOfOrdinals],ECX
         MOV [EBX+CTX_FOR.OrdinalNr],EAX ; Start with uninitialized ordinal number.
         MOV [EBX+CTX_FOR.Step+0],EAX ; Assume default step.
         MOV [EBX+CTX_FOR.Step+4],EAX
         ; Resolve keyword STEP= if present, otherwise leave default STEP=0.
         MOV EAX,[%Stm]
         BufferRetrieve [EAX+STM.KeyBuffer]
         JECXZ .60:
     .40:Invoke DictLookup::,DictForKeys::,[ESI+0],[ESI+4] ; Only STEP= expected.
         Msg cc=C,'3860',ESI ; Unexpected %FOR option "!1S=". Ignored.
         JC .50:
         Invoke ExpEvalNum::,[ESI+8],[ESI+12]
         JC.50:
         MOV [EBX+CTX_FOR.Step+0],EAX
         MOV [EBX+CTX_FOR.Step+4],EDX
         OR EAX,EDX
         JZ .50:
         RstSt [EDI+CTX.Status],ctxStep0
     .50:ADD ESI,16 ; Inspect other keyword operands, if any, to detect unexpected keys.
         SUB ECX,16
        ; JA .40:
         JG .40:
     .60:; EBX=^CTX_FOR is initialized. EDI=^CTX.
         ; Prepare formal variable name to CTX.FrmBuffer, persistently on pass pool.
         MOV EBX,[%Stm]
         MOV ECX,[EBX+STM.LabelSize]
         PoolStore [%ForPassPool],[EBX+STM.LabelPtr],ECX
         MOV EDX,EAX ; Ptr to persistent formal name.
         BufferNew [EDI+CTX.FrmBuffer],16
         SUB ESI,ESI
         MOV [EAX+0],EDX ; Persistent formal name pointer.
         MOV [EAX+4],ECX ; Formal name size.
         MOV [EAX+8],ESI ; Formal value is not set yet.
         MOV [EAX+12],ESI
         ; Store statement ordinals to context.OrdBuffer with values persistent in .ValBuffer.
         BufferRetrieve [EBX+STM.OrdBuffer]
         JECXZ .80:
     .70:MOV EAX,[ESI+0] ; %FOR statement ordinal value ptr.
         MOV EDX,[ESI+4] ; %FOR statement ordinal value size.
         PoolStore [%ForPassPool],EAX,EDX
         MOV EBX,EAX ; Persistent ordinal value ptr.
         BufferNew [EDI+CTX.OrdBuffer],8
         MOV [EAX+0],EBX
         MOV [EAX+4],EDX
         ADD ESI,8
         SUB ECX,8
         JA .70: ; Copy all statement ordinals.
     .80:Invoke CtxForNext::,EDI ; Prepare formal variable for the 1st ot next expansion.
         JC .85: ; Exit if no more expansions required by %FOR ordinals.
         BufferRetrieve [EDI+CTX.FrmBuffer] ; 4*DD with formal name and value.
         JECXZ .85:
         Invoke LstSet::,[ESI+8],[ESI+12]
         Invoke CtxExpansionNrUpdate::,EDI,[%Stm]
         JNC .90:
     .85:SetSt [EDI+CTX.Status],ctxNoEmit+ctxExited ; If no more expansions or %MAXEXPANSIONS reached.
         SetSt [Src.Lst.Status::],lstNoData
     .90:EndProcedure PseudopcFOR

↑ PseudopcEXITFOR Stm
  Pseudoinstruction %EXITFOR handler.
Manual
  %EXITFOR
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxFind StmCheckFields
Tested by
  t2642

    PseudopcEXITFOR Procedure Stm
         MOV EBX,[%Stm]
         SetSt [Src.Lst.Status::],lstNoData
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90:
         JNSt [EBX+STM.CtxStatusAll],ctx1stRepeat,.30:
         Invoke StmCheckFields::,EBX,"00?0"
    .30: Invoke CtxFind::, ctxFOR,EBX
         JNC .50:
         JNSt [EBX+STM.CtxStatusAll],ctx1stRepeat,.90:
         Msg '7120',Dict_PseudopcEXITFOR:: ; Wrong nesting, unexpected !1S.
         JMP .90:
    .50: JZ .80: ; If blockId match.
         JNSt [EBX+STM.CtxStatusAll],ctx1stRepeat,.80:
         Msg '7110',Dict_PseudopcEXITFOR::,EAX ; Wrong nesting, expected "!1S !2S".
    .80: SetSt [EAX+CTX.Status],ctxNoEmit+ctxExited ; Do not emit until %ENDFOR.
    .90:EndProcedure PseudopcEXITFOR

↑ PseudopcENDFOR Stm
  Pseudoinstruction %ENDFOR handler.
Manual
  %ENDFOR
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxDiscard CtxFind StmCheckFields
Tested by
  t2640 t2641 t2642

    PseudopcENDFOR Procedure Stm
         MOV EBX,[%Stm]
         SetSt [Src.Lst.Status::],lstNoData
         Invoke CtxFind::,ctxFOR,EBX
         Msg cc=C,'7120',Dict_PseudopcENDFOR:: ; Wrong nesting, unexpected !1S.
         JC .90:
         JE .20: ; If blockId matched.
         JNSt [EBX+STM.CtxStatusAll],ctx1stRepeat,.20:
         Msg '7110',Dict_PseudopcENDFOR::,EAX ; Wrong nesting, expected "!1S !2S".
     .20:MOV EDI,EAX ; ^CTX FOR.
     .30:; JSt [EDI+CTX.Status],ctxNoEmit, .70:
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit, .70:
         ; FOR block not exited yet, leave context EDI on stack and goto %FOR statement.
         RstSt [EDI+CTX.Status],ctx1stRepeat
         MOV ECX,[EDI+CTX.LinePtr]
         MOV EDX,[EDI+CTX.ChunkPtr]
         MOV [EBX+STM.LineNext],ECX ; Continue expansion, go back to the %FOR statement.
         MOV [EBX+STM.ChunkNext],EDX
         JMPS .90: ; and leave FOR context on stack.
     .70:JNSt [EBX+STM.CtxStatusAll],ctx1stRepeat,.80:
         Invoke StmCheckFields::,EBX,"00?0"
     .80:Invoke CtxDiscard::,EDI,EBX
     .90:EndProcedure PseudopcENDFOR

↑ PseudopcIF Stm
  Pseudoinstruction %IF handler.
Manual
  %IF
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxCreate ExpEvalBoolOp1 LstBoolean StmCheckFields
Tested by
  t2602

    PseudopcIF Procedure Stm
         MOV EBX,[%Stm]
         SetSt [Src.Lst.Status::],lstNoData
         MOV ECX,[EBX+STM.CtxStatusAll]
         AND ECX,ctxNoEmit
         JNZ .60:
         OR ECX,ctxIfEmit ; %IF block in emitting status.
         RstSt [Src.Lst.Status::],lstNoData
         Invoke StmCheckFields::,EBX,"?0?0"
         JC .50:
         Invoke ExpEvalBoolOp1::,EBX
         Invoke LstBoolean::
         JA .60: ; Jmp if TRUE
     .50:OR ECX,ctxNoEmit
     .60:OR ECX,ctxIF
         StackPush [Src.CtxStack::],0
         Invoke CtxCreate::,EAX,ECX,EBX
     .90:EndProcedure PseudopcIF

↑ PseudopcELSE Stm
  Pseudoinstruction %ELSE handler.
Manual
  %ELSE
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxFind LstBoolean StmCheckFields
Tested by
  t2602

    PseudopcELSE Procedure Stm
         MOV EBX,[%Stm]
         SetSt [Src.Lst.Status::],lstNoData
         Invoke CtxFind::,ctxIF,EBX
         Msg cc=C,'7120',Dict_PseudopcELSE:: ; Wrong nesting, unexpected !1S.
         JC .90:
         JE .30: ; If blockId matched.
         JSt [EAX+CTX.Status],ctxIfEmit,.30: ; If %IF block was enterred in emitting state.
         SetSt [EAX+CTX.Status],ctxNoEmit ; %IF block enterred as NoEmit. Both branches are NoEmit.
         JMP .90:
     .30:Invoke StmCheckFields::,EBX,"00?0"
         JNSt [EAX+CTX.Status],ctxElsed,.50:
         Msg '7122' ; %ELSE was already used in this %IF/%ENDIF block. Ignored.
         JMP .90:
     .50:JNSt [EAX+CTX.Status],ctxIfEmit,.70: ; If %IF block was enterred in nonemitting state.
         TESTD [EAX+CTX.Status],ctxNoEmit
         Invoke LstBoolean:: ; List TRUE/FALSE in listing dump column.
     .70:InvSt [EAX+CTX.Status],ctxNoEmit ; Reverse the condition.
         SetSt [EAX+CTX.Status],ctxElsed
         RstSt [Src.Lst.Status::],lstNoData
     .90:EndProcedure PseudopcELSE

↑ PseudopcENDIF Stm
  Pseudoinstruction %ENDIF handler.
Manual
  %ENDIF
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxDiscard CtxFind StmCheckFields
Tested by
  t2602

    PseudopcENDIF Procedure Stm
         MOV EBX,[%Stm]
         SetSt [Src.Lst.Status::],lstNoData
         Invoke CtxFind::,ctxIF,EBX
         Msg cc=C,'7120',Dict_PseudopcENDIF:: ; Wrong nesting, unexpected !1S.
         JC .90:
         JE .20: ; If blockId matched.
         JNSt [EBX+STM.CtxStatusAll],ctx1stRepeat,.20:
         Msg '7110',Dict_PseudopcENDIF::,EAX ; Wrong nesting, expected "!1S !2S".
    .20: Invoke StmCheckFields::,EBX,"00?0"
         Invoke CtxDiscard::,EAX,EBX
     .90:EndProcedure PseudopcENDIF

↑ PseudopcMACRO Stm
  Pseudoinstruction %MACRO handler.
Manual
  %MACRO
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxCreate CtxExpansionNrUpdate CtxPeek ExpParseIdentifier MacFind MacPrototype StmCheckFields SymCreate
Tested by
  t2800 t7215

    PseudopcMACRO Procedure Stm
         MOV EBX,[%Stm]
         SetSt [Src.Lst.Status::],lstNoData
         JNSt [EBX+STM.CtxStatusAll],ctxNoEmit,.30:
         ; In noemitting context only push ctxMACRO (%MACRO definition in %MACRO).
         StackPush [Src.CtxStack::],0
         Invoke CtxCreate::,EAX,ctxMACRO+ctxDefinition+ctxNoEmit,EBX
         JMP .90:
     .30:; Emitting context, either macro declaration in normal stm flow, or expansion.
         Invoke StmCheckFields::,EBX,"10**"
         JC .80:
         JNSt [EBX+STM.CtxStatusAll],ctxPrototype,.50:
         ; We were sent here from macro invocation to update macro prototype and expand it.
         Invoke CtxPeek::,ctxMACRO,0 ; Macro expanding context already on stack does not change.
         JC .F9971:
         MOV EDI,EAX ; Context MACRO+Prototype.
         JNSt [EDI+CTX.Status],ctxPrototype,.F9971:
         Invoke MacPrototype::,EDI,EBX
         RstSt [EDI+CTX.Status],ctxPrototype
         Invoke CtxExpansionNrUpdate::,EDI,EBX
         JSt [EDI+CTX.Status],ctxMacLabeled,.90:
         ; There is no %: label in macro-definition body. Let us put macro label here, if any exists.
         BufferRetrieve [EDI+CTX.ObjBuffer]
         MOV EDX,[ESI+CTX_MAC.InvokStmStatus]
         MOV ECX,[ESI+CTX_MAC.LabelSize]
         MOV ESI,[ESI+CTX_MAC.LabelPtr]
         ; Invocation label is now ESI,ECX. As the macro-definition is not explicitly labeled,
         ;    the label will be defined right here, at the start of expansion.
         JECXZ .40: ; If no label used on macro invocation.
         CMP ECX,1
         JNE .34:
         CMPB [ESI],'$'
         JE .90: ; Macro was invoked with label $, ignore it.
     .34:AND EDX,stmLabelIsPublic
         SetSt [EBX+STM.Status],EDX
         MOVB [EBX+STM.Status],'A' ; Implicit macro label is type Address.
         SetSt EDX,symDefined
         Invoke SymCreate::,EDX,ESI,ECX,EBX
     .40:JMP .90:
    .F9971:Msg '9971' ; Internal error: unexpected error on macro expansion.
         JMP .90:
     .50:; We were sent here in normal flow of reading source: macro is being declared.
         MOV ESI,[EBX+STM.LabelPtr]
         MOV ECX,[EBX+STM.LabelSize]
         LEA EDX,[ESI+ECX]
         Invoke ExpParseIdentifier::,ESI,EDX,0
         CMP EAX,ECX
         Msg cc=NE,'7319' ; Invalid character in the macro name.
         JNE .90:
         Invoke MacFind::, ESI,ECX
         Msg cc=NC,'2512',EBX,[EAX+MAC.LinePtr] ; Overwriting macro !1S previously defined at !2@.
         MOV ECX,[EBX+STM.Program]
         TEST ECX
         JZ .F9971:
         MOV ESI,[ECX+PGM.PassPtr]
         TEST ESI ; ESI=^PASS
         JZ .F9971:
         MOV ECX,EAX ; Either 0 or ^MAC if the macro was already defined.
         JECXZ .60:
         ListStore [ESI+PASS.MacList],ECX ; Copy previously defined macro.
         MOV EDI,EAX ; ^MAC on MacList.
         JMPS .70:
     .60:ListNew [ESI+PASS.MacList]
         MOV EDI,EAX ; ^MAC New empty leaf of MacList.
         MOV EAX,[EBX+STM.LabelPtr]
         MOV ECX,[EBX+STM.LabelSize]
         PoolStore [ESI+PASS.Pool],EAX,ECX
         JC .F9971:
         MOV [EDI+MAC.NamePtr],EAX
         MOV [EDI+MAC.NameSize],ECX
     .70:MOV EAX,[EBX+STM.LinePtr]
         MOV [EDI+MAC.LinePtr],EAX
         MOVD [EDI+MAC.Status],0
     .80:StackPush [Src.CtxStack::],0
         Invoke CtxCreate::,EAX,ctxMACRO+ctxDefinition+ctxFormal+ctxNoEmit,EBX
         MOV [EAX+CTX.MacPtr],EDI
     .90:EndProcedure PseudopcMACRO

↑ PseudopcEXITMACRO Stm
  Pseudoinstruction %EXITMACRO handler.
Manual
  %EXITMACRO
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxFind StmCheckFields

    PseudopcEXITMACRO Procedure Stm
         SetSt [Src.Lst.Status::],lstNoData
         MOV EBX,[%Stm]
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90:
         Invoke StmCheckFields::,EBX,"00?0"
         Invoke CtxFind::, ctxMACRO,EBX
         Msg cc=C,'7120',Dict_PseudopcEXITMACRO:: ; Wrong nesting, unexpected !1S.
         JC .90:
         Msg cc=NE,'7110',Dict_PseudopcEXITMACRO::,EAX ; Wrong nesting, expected "!1S !2S".
         SetSt [EAX+CTX.Status],ctxNoEmit+ctxExited ; Do not emit until %ENDMACRO
    .90:EndProcedure PseudopcEXITMACRO

↑ PseudopcENDMACRO Stm
  Pseudoinstruction %ENDMACRO handler.
Manual
  %ENDMACRO
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxDiscard CtxFind StmCheckFields
Tested by
  t2800

    PseudopcENDMACRO Procedure Stm
         SetSt [Src.Lst.Status::],lstNoData
         MOV EBX,[%Stm]
         Invoke CtxFind::,ctxMACRO,EBX
         Msg cc=C,'7120',Dict_PseudopcENDMACRO:: ; Wrong nesting, unexpected !1S.
         JC .90:
         Msg cc=NE,'7110',Dict_PseudopcENDMACRO::,EAX ; Wrong nesting, expected "!1S !2S".
    .20: MOV EDI,EAX ; ^CTX MACRO.
         JNSt [EDI+CTX.Status],ctxMacLabeled,.40:
         MOV EAX,[EDI+CTX.MacPtr]
         TEST EAX
         JZ .40:
         SetSt [EAX+MAC.Status],macLabeled
    .40: JSt [EDI+CTX.Status],ctxDefinition,.50:
         JNSt [EDI+CTX.Status],ctxExpansion,.50:
         ; Macro expansion ends. Assembly continues after macro invocation statement, saved in context.
         MOV EAX,[EDI+CTX.LineNext]
         MOV EDX,[EDI+CTX.ChunkNext]
         MOV [EBX+STM.LineNext],EAX
         MOV [EBX+STM.ChunkNext],EDX
         SetSt [Src.Lst.Status::],lstAsRepeated ; Separate listing column with '+'
     .50:Invoke StmCheckFields::,EBX,"00?0" ; Macro definition ends.
     .80:Invoke CtxDiscard::,EDI,EBX
     .90:EndProcedure PseudopcENDMACRO

↑ PseudopcSHIFT Stm
  Pseudoinstruction %SHIFT handler.
Manual
  %SHIFT
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxPeek ExpEvalNum StmCheckFields

    PseudopcSHIFT Procedure Stm
         SetSt [Src.Lst.Status::],lstNoData        ; Empty the dump column in listing.
         MOV EBX,[%Stm]
         StmInStruc EBX,.90:                       ; Do not allow this statement in a structure definition.
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90: ; Do nothing in nonemitting state.
         Invoke StmCheckFields::,EBX,"00?0"        ; Tolerate zero or one ordinal operand.
         JC .90:
         Invoke CtxPeek::, ctxMACRO,0              ; %SHIFT is acceptable only in macro context.
         Msg cc=C,'7120',Dict_PseudopcSHIFT::      ; Wrong nesting, unexpected !1S.
         JC .90:
         MOV EDI,EAX ; ^CTX
         BufferRetrieve [EBX+STM.OrdBuffer]
         MOV EAX,1 ; Default is %SHIFT +1.
         JECXZ .50:
         Invoke ExpEvalNum::,[ESI+0],[ESI+4]
         JC .90:
    .50: ADD [EDI+CTX.Shift],EAX                   ; Apply the shift value on the macro context.
    .90:EndProcedure PseudopcSHIFT

↑ PseudopcDROPMACRO Stm
  Pseudoinstruction %DROPMACRO handler.
Manual
  %DROPMACRO
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxPeek MacFind StmCheckFields
Tested by
  t2800

    PseudopcDROPMACRO Procedure Stm
         SetSt [Src.Lst.Status::],lstNoData
         MOV EBX,[%Stm]
         StmInStruc EBX,.90: ; Do not allow this statement in a structure definition.
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90:
         Invoke StmCheckFields::,EBX,"00+0"
         JC .90:
         SetSt [Src.Lst.Status::],lstNoData
         ; Check if %DROPMACRO has just one operand * (drop all macros).
         CMP [EBX+STM.NrOfOrdinals],1
         JNE .30:
         BufferRetrieve [EBX+STM.OrdBuffer]
         MOV ECX,[ESI+4]
         CMP ECX,1
         JNE .30:
         MOV ESI,[ESI+0]
         CMPB [ESI],'*'
         JNE .30:
         ; %DROPMACRO * - drop all macros declared so far in current PGM and parents.
         SUB EDI,EDI
     .10:Invoke CtxPeek::, ctxPROGRAM, EDI ; Find PGM on context stack.
         JC .90:  ; End if no more programs.
         MOV EDI,EAX ; Context pointer.
         MOV EBX,[EAX+CTX.ObjPtr] ; Get the program to EBX.
         TEST EBX
         JZ .10:
         MOV ECX,[EBX+PGM.PassPtr]
         JECXZ .10:
         MOV EDX,[ECX+PASS.MacList]
         ListGetLast EDX
     .20:JZ .10:
         MOV [EAX+DICT.Data],0 ; Actual erasing of the macro EAX.
         ListGetPrev EAX
         JMP .20:
     .30:; Pseudoinstruction %DROPMACRO has explicitly enumerated macro names.
         ; Find current program.pass.MacList to EDX.
         ; Cannot use Invoke MacFind because only current program's macro can be %dropped.
         MOV ECX,[EBX+STM.Program]
         TEST ECX
         JZ .90:
         MOV ECX,[ECX+PGM.PassPtr]
         TEST ECX
         JZ .90:
         MOV EDX,[ECX+PASS.MacList]
         BufferRetrieve [EBX+STM.OrdBuffer]
         SAR ECX,3
         JZ .90:
     .40:ListGetLast EDX
     .50:JZ .60:
         Compare [EAX+DICT.Ptr],[EAX+DICT.Size],[ESI+0],[ESI+4]
         JE .70:
         ListGetPrev EAX
         JMP .50:
     .60: ; Macro was not found in current program, let's search parents to learn if W2515 is due.
         Invoke MacFind::,[ESI+0],[ESI+4]
         Msg cc=C,'2515',PgmStatus=pgmLastPass,ESI ; Macro !1S was not found, cannot be dropped.
         ListStore EDX,ESI ; Create new DICT record on MacList with dropped macro name.
        ; The actual %DROPMACRO action is realized as zeroing current program's Maclist DICT.Data.
     .70:MOVD [EAX+DICT.Data],0  ; Actual erasing of the macro EAX.
         ADD ESI,8
         LOOP .40: ; Repeat with each %DROPMACRO operand.
    .90:EndProcedure PseudopcDROPMACRO

↑ PseudopcREPEAT Stm
  Pseudoinstruction %REPEAT handler. PseudopcREPEAT opens %REPEAT/%ENDREPEAT block. It is processed when
  1. %REPEAT is encounterred in ordinary statements flow
  2. %ENDREPEAT returned statement flow to reassemble the block. In the 2nd case new context is not created and the existing ctxREPEAT is reused.
Manual
  %REPEAT
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  Ctx1stRepeat CtxCreate CtxExpansionNrUpdate StmCheckFields
Tested by
  t2750 t2752

    PseudopcREPEAT Procedure Stm
         SetSt [Src.Lst.Status::],lstNoData
         MOV EBX,[%Stm]
         StackPeekLast [Src.CtxStack::]
         JC .90:
         JNSt [EAX+CTX.Status],ctxREPEAT,.30:
         MOV EDI,EAX ; ^CTX REPEAT.
         MOV EAX,[EDI+CTX.LinePtr]
         CMP EAX,[EBX+STM.LinePtr]
         JE .50: ; Do not push new ctxREPEAT if %REPEAT block continues expansion.
     .30:; New context will be created.
         Invoke StmCheckFields::,EBX,"00?0"
         Invoke Ctx1stRepeat:: ;Returns EAX=ctx1stRepeat only if all repeating contexts have it too.
         MOV ECX,ctxREPEAT+ctxExpandable+ctxExpansion+ctxRepeat
         OR ECX,EAX ; Incorporate ctx1stRepeat.
         StackPush [Src.CtxStack::],0
         MOV EDI,EAX
         Invoke CtxCreate::,EDI,ECX,EBX
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.70:
     .50:Invoke CtxExpansionNrUpdate::,EDI,EBX
         JNC .90:
     .70:SetSt [EDI+CTX.Status],ctxNoEmit+ctxExited
     .90:EndProcedure PseudopcREPEAT

↑ PseudopcEXITREPEAT Stm
  Pseudoinstruction %EXITREPEAT handler.
Manual
  %EXITREPEAT
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxFind StmCheckFields
Tested by
  t2752

    PseudopcEXITREPEAT Procedure Stm
         SetSt [Src.Lst.Status::],lstNoData
         MOV EBX,[%Stm]
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90:
         JNSt [EBX+STM.CtxStatusAll],ctx1stRepeat,.30:
         Invoke StmCheckFields::,EBX,"00?0"
    .30: Invoke CtxFind::, ctxREPEAT,EBX
         JNC .50:
         JNSt [EBX+STM.CtxStatusAll],ctx1stRepeat,.90:
         Msg '7120',Dict_PseudopcEXITREPEAT:: ; Wrong nesting, unexpected !1S.
         JC .90:
    .50: JZ .80:
         JNSt [EBX+STM.CtxStatusAll],ctx1stRepeat,.80:
         Msg '7110',Dict_PseudopcEXITREPEAT::,EAX ; Wrong nesting, expected "!1S !2S".
    .80: SetSt [EAX+CTX.Status],ctxNoEmit+ctxExited ; Do not emit until %ENDREPEAT.
    .90:EndProcedure PseudopcEXITREPEAT

↑ PseudopcENDREPEAT Stm
  Pseudoinstruction %ENDREPEAT handler.
Manual
  %ENDREPEAT
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxDiscard CtxFind ExpEvalBoolOp1 LstBoolean StmCheckFields
Invoked by
  PseudopcUNTIL
Tested by
  t2750 t2752

    PseudopcENDREPEAT Procedure Stm
         MOV EBX,[%Stm]
         Invoke CtxFind::,ctxREPEAT,EBX
         Msg cc=C,'7120',Dict_PseudopcENDREPEAT:: ; Wrong nesting, unexpected !1S.
         JC .90:
         JE .20:
         JNSt [EBX+STM.CtxStatusAll],ctx1stRepeat,.20:
         Msg '7110',EAX,Dict_PseudopcENDREPEAT::,EAX ; Wrong nesting, expected "!1S !2S".
    .20: MOV EDI,EAX ; ^CTX REPEAT.
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.70:
         Invoke ExpEvalBoolOp1::, EBX
         Invoke LstBoolean::
         JC  .70: ; Block ends if error.
         JNZ .70: ; Block ends if TRUE.
     ; %UNTIL condition is FALSE, leave context EDI on stack and go back to %REPEAT.
         RstSt [EDI+CTX.Status],ctx1stRepeat
         MOV EAX,[EDI+CTX.LinePtr]
         MOV EDX,[EDI+CTX.ChunkPtr]
         MOV [EBX+STM.LineNext],EAX ; Continue expansion, go back to %REPEAT.
         MOV [EBX+STM.ChunkNext],EDX
         JMPS .90:
     .70:Invoke StmCheckFields::,EBX,"?0?0"
         Invoke CtxDiscard::,EDI,EBX
     .90:EndProcedure PseudopcENDREPEAT

↑ PseudopcUNTIL Stm
  Pseudoinstruction %UNTIL handler, implemented as alias to %ENDREPEAT.
Manual
  %UNTIL
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  PseudopcENDREPEAT

    PseudopcUNTIL Procedure Stm
        Invoke PseudopcENDREPEAT, [%Stm]
        EndProcedure PseudopcUNTIL

↑ PseudopcSET Stm
  Pseudoinstruction %SET handler.
Manual
  %SET
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  EaBufferRelease EaBufferReserve LstSet StmCheckFields VarAssign VarCheckId
Tested by
  t2810

    PseudopcSET Procedure Stm
         MOV EBX,[%Stm]
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.99:
         Invoke StmCheckFields::, EBX, '10**'
         JC .99:
         Invoke VarCheckId::,[EBX+STM.LabelPtr],[EBX+STM.LabelSize]
         JC .99:
         Invoke EaBufferReserve::, PseudopcSET
         MOV EDX,EAX
         ; %SET will concatenate ordinal and keyword operands, separated with comma.
         BufferRetrieve [EBX+STM.OrdBuffer]
        JECXZ .30:
    .10: ; ESI points to Ptr,Size of ordinal.
         BufferStore EDX,[ESI],[ESI+4]
         BufferStore EDX, =B',',1
         ADD ESI,8
         SUB ECX,8
         JA .10:
    .30: BufferRetrieve [EBX+STM.KeyBuffer]
         JECXZ .50:
    .40: BufferStore EDX,[ESI],[ESI+4]
         BufferStore EDX,=B'=',1
         BufferStore EDX,[ESI+8],[ESI+12]
         BufferStore EDX,=B',',1
         ADD ESI,16
         SUB ECX,16
         JG .40:
    .50: BufferDecrement EDX ; Omit the last comma, if at least one was stored.
         BufferRetrieve EDX
         MOV EAX,[EBX+STM.Program]
         JNSt [EAX+PGM.Status],pgmLastPass,.97:
         Invoke LstSet::,ESI,ECX
    .97: Invoke VarAssign::,EBX,EDX  ; Value of %variable is in buffer EDX.
         Invoke EaBufferRelease::,EDX
    .99:EndProcedure PseudopcSET

↑ PseudopcSET2 Stm
  Pseudoinstruction %SET2 handler.
Manual
  %SET2
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  EaBufferRelease EaBufferReserve LstSet StmCheckFields VarAssign VarExpandField
Tested by
  t2871 t2881

    PseudopcSET2 Procedure Stm
         MOV EBX,[%Stm]
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.99:
         Invoke StmCheckFields::, EBX, '10**'
         JC .99:
         Invoke EaBufferReserve::,PseudopcSET2
         MOV EDX,EAX
         ; %SET2 will concatenate ordinal and keyword operands, separated with comma.
         BufferRetrieve [EBX+STM.OrdBuffer]
         JECXZ .30:
    .10: ; ESI points to Ptr,Size of ordinal.
         BufferStore EDX,[ESI],[ESI+4]
         BufferStore EDX, =B',',1
         ADD ESI,8
         SUB ECX,8
         JA .10:
    .30: BufferRetrieve [EBX+STM.KeyBuffer]
         JECXZ .50:
    .40: BufferStore EDX,[ESI],[ESI+4]
         BufferStore EDX,=B'=',1
         BufferStore EDX,[ESI+8],[ESI+12]
         BufferStore EDX,=B',',1
         ADD ESI,16
         SUB ECX,16
         JG .40:
    .50: BufferDecrement EDX ; Omit the last comma, if at least one was stored.
         BufferRetrieve EDX
         ADD ECX,ESI
         Invoke EaBufferReserve::,PseudopcSET2.50
         Invoke VarExpandField::,ESI,ECX,EAX,-1 ; Second expansion.
         Invoke EaBufferRelease::,EDX
         Invoke VarAssign::,EBX,EAX  ; Value of %variable is in buffer EAX.
         MOV ECX,[EBX+STM.Program]
         JNSt [ECX+PGM.Status],pgmLastPass,.98:
         BufferRetrieve EAX
         Invoke LstSet::,ESI,ECX
    .98: Invoke EaBufferRelease::,EAX
    .99:EndProcedure PseudopcSET2

↑ PseudopcSETA Stm
  Pseudoinstruction %SETA handler.
Manual
  %SETA
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  EaBufferRelease EaBufferReserve ExpConvertToNumber ExpEval ExpReportError LstSet StmCheckFields VarAssign VarCheckId
Tested by
  t2821

    PseudopcSETA Procedure Stm
    StmSaExp LocalVar Size=SIZE#EXP ; Evaluated EXP.
    StmSaBuf LocalVar ; Temporary ^buffer.
    StmSaDec LocalVar Size=20 ; Decadic value storage.
         MOV EBX,[%Stm]
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.99:
         Invoke StmCheckFields::, EBX, '10*0'
         JC .99:
         Invoke VarCheckId::,[EBX+STM.LabelPtr],[EBX+STM.LabelSize]
         JC .99:
         Invoke EaBufferReserve::, PseudopcSETA
         MOV [%StmSaBuf],EAX ; Temorary buffer for %variable value.
         MOV EDX,EAX
         ; %SETA will calculate each ordinal operand and store decadic value as a list to EDX.
         BufferRetrieve [EBX+STM.OrdBuffer]
         JECXZ .30:
    .10: ; ESI points to Ptr,Size of ordinal.
         LEA EDX,[%StmSaExp]
         Invoke ExpEval::,EDX,[ESI],[ESI+4],EBX
         Invoke ExpReportError::,EDX
         JC .20:
         Invoke ExpConvertToNumber::,EDX
         Msg cc=C,'7332',PgmStatus=pgmLastPass ; Plain numeric value or expression expected.
         JC .20:
         PUSH ECX
          LEA EDI,[%StmSaDec]
          MOV EAX,[EDX+EXP.Low]
          MOV EDX,[EDX+EXP.High]
          MOV ECX,EDI
          StoQD EDI
          SUB EDI,ECX
          BufferStore [%StmSaBuf],ECX,EDI
         POP ECX
    .20: ADD ESI,8
         SUB ECX,8
         JNA .30:
         BufferStore [%StmSaBuf],=B',',1
         JMP .10:
    .30: Invoke VarAssign::,EBX,[%StmSaBuf]
         MOV EAX,[EBX+STM.Program]
         JNSt [EAX+PGM.Status],pgmLastPass,.98:
         BufferRetrieve [%StmSaBuf]
         Invoke LstSet::,ESI,ECX
    .98: Invoke EaBufferRelease::,[%StmSaBuf]
    .99:EndProcedure PseudopcSETA

↑ PseudopcSETB Stm
  Pseudoinstruction %SETB handler.
Manual
  %SETB
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  EaBufferRelease EaBufferReserve ExpEvalBoolean LstSet StmCheckFields VarAssign VarCheckId
Tested by
  t2831

    PseudopcSETB Procedure Stm
         MOV EBX,[%Stm]
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.99:
         Invoke StmCheckFields::, EBX, '10*0'
         JC .99:
         Invoke VarCheckId::,[EBX+STM.LabelPtr],[EBX+STM.LabelSize]
         JC .99:
         Invoke EaBufferReserve::, PseudopcSETB
         MOV EDX,EAX ; Temorary buffer for %variable value.
         BufferRetrieve [EBX+STM.OrdBuffer]
         JECXZ .20: ; If no operand, treat this as FALSE.
    .10: ; ESI points to Ptr,Size of ordinal.
         Invoke ExpEvalBoolean::,[ESI+0],[ESI+4]
         JBE .20:
         BufferStore EDX,=B'1',1
         JMPS .30:
    .20: BufferStore EDX,=B'0',1
    .30: ADD ESI,8
         SUB ECX,8
         JG .10:
    .50: Invoke VarAssign::,EBX,EDX
         MOV EAX,[EBX+STM.Program]
         JNSt [EAX+PGM.Status],pgmLastPass,.80:
         BufferRetrieve EDX
         Invoke LstSet::,ESI,ECX
     .80:Invoke EaBufferRelease::,EDX
    .99:EndProcedure PseudopcSETB

↑ PseudopcSETC Stm
  Pseudoinstruction %SETC handler.
Manual
  %SETC
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  EaBufferRelease EaBufferReserve ExpConvertToNumber ExpEval ExpReportError LstSet StmCheckFields VarAssign VarCheckId
Tested by
  t2841

    PseudopcSETC Procedure Stm
    StmScExp  LocalVar Size=SIZE#EXP ; Evaluated EXP.
    StmScBuf  LocalVar ; Temporary ^buffer.
    StmScChar LocalVar ; ANSI-character value storage.
         MOV EBX,[%Stm]
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.99:
         Invoke StmCheckFields::, EBX, '10*0'
         JC .99:
         Invoke VarCheckId::,[EBX+STM.LabelPtr],[EBX+STM.LabelSize]
         JC .99:
         Invoke EaBufferReserve::, PseudopcSETC
         MOV [%StmScBuf],EAX ; Temorary buffer for %variable value.
         MOV EDX,EAX
         ; %SETC will calculate each ordinal operand and store char as a string to buffer.
         BufferRetrieve [EBX+STM.OrdBuffer]
         JECXZ .30:
    .10: ; ESI points to Ptr,Size of ordinal.
         LEA EDX,[%StmScExp]
         Invoke ExpEval::,EDX,[ESI],[ESI+4],EBX
         Invoke ExpReportError::,EDX
         JC .20:
         Invoke ExpConvertToNumber::,EDX
         Msg cc=C,'7332',PgmStatus=pgmLastPass ; Plain numeric value or expression expected.
         JC .20:
         PUSH ECX
          LEA EDI,[%StmScChar]
          MOV EAX,[EDX+EXP.Low]
          MOV [EDI],AL
          MOV ECX,EAX
          AND EAX,0xFFFFFF00
          OR EAX,[EDX+EXP.High]
          Msg cc=NZ,'7333',ECX ; Value !1D does not fit as 8bit character.',0
          BufferStore [%StmScBuf],EDI,1
         POP ECX
    .20: ADD ESI,8
         SUB ECX,8
         JA .10:
    .30: Invoke VarAssign::,EBX,[%StmScBuf]
         MOV EAX,[EBX+STM.Program]
         JNSt [EAX+PGM.Status],pgmLastPass,.98:
         BufferRetrieve [%StmScBuf]
         Invoke LstSet::,ESI,ECX
    .98: Invoke EaBufferRelease::,[%StmScBuf]
    .99:EndProcedure PseudopcSETC

↑ PseudopcSETE Stm
  Pseudoinstruction %SETE handler.
Manual
  %SETE
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  EaBufferRelease EaBufferReserve LstSet StmCheckFields VarAssign VarCheckId

    PseudopcSETE Procedure Stm
    StmSeBuf LocalVar                                ; Temporary ^buffer.
         MOV EBX,[%Stm]
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.99:
         Invoke StmCheckFields::, EBX, '10*0'
         JC .99:
         Invoke VarCheckId::,[EBX+STM.LabelPtr],[EBX+STM.LabelSize]
         JC .99:
         Invoke EaBufferReserve::, PseudopcSETE
         MOV [%StmSeBuf],EAX                         ; Temorary buffer for %variable value.
         ; %SETE will calculate each ordinal operand and store text value as a list.
         BufferRetrieve [EBX+STM.OrdBuffer]
         JECXZ .30:
    .10: MOV EDI,[ESI]                               ; ESI points to Ptr,Size of ordinal.
         MOV EDX,[ESI+4]
         MOV EAX,[%StmSeBuf]
         SysGetEnvironment EDI,EDX,EAX
         Msg cc=Z,'2520',ESI                         ; Environment variable "!1S" is undefined or empty.
         ADD ESI,8
         SUB ECX,8
         JNA .30:
         BufferStore [%StmSeBuf],=B',',1
         JMP .10:
    .30: Invoke VarAssign::,EBX,[%StmSeBuf]
         MOV EAX,[EBX+STM.Program]
         JNSt [EAX+PGM.Status],pgmLastPass,.98:
         BufferRetrieve [%StmSeBuf]
         Invoke LstSet::,ESI,ECX
    .98: Invoke EaBufferRelease::,[%StmSeBuf]
    .99:EndProcedure PseudopcSETE

↑ PseudopcSETL Stm
  Pseudoinstruction %SETL handler.
Manual
  %SETL
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  EaBufferRelease EaBufferReserve ExpCountItems LstSet StmCheckFields VarAssign VarCheckId VarExpand VarParseName
Tested by
  t2866

    PseudopcSETL Procedure Stm
    StmSlBuf LocalVar ; Temporary ^buffer.
    StmSlDec LocalVar Size=20                        ; Decadic value storage.
         MOV EBX,[%Stm]
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.99:
         Invoke StmCheckFields::, EBX, '1010'
         JC .99:
         Invoke VarCheckId::,[EBX+STM.LabelPtr],[EBX+STM.LabelSize]
         JC .99:
         Invoke EaBufferReserve::, PseudopcSETL
         MOV [%StmSlBuf],EAX
         BufferRetrieve [EBX+STM.OrdBuffer]
         MOV ECX,[ESI+4]
         MOV ESI,[ESI]                               ; ESI,ECX should be unexpanded %variable name.
         LEA EDX,[ESI+ECX]
         PUSH ESI
           Invoke VarParseName::,ESI,EDX
         POP ESI
         Msg cc=C,'7841'                             ; %%SETS and %%SETL expect %%variable name as the only operand.
         JC .95:
         Invoke VarExpand::,ESI,EDX,[%StmSlBuf],-1
         ; EAX= is pointer behind the parsed %variable name and its suboperations.
         BufferRetrieve [%StmSlBuf]
         BufferClear [%StmSlBuf]
         Invoke ExpCountItems::,ESI,ECX
         LEA EDI,[%StmSlDec]
         SUB EDX,EDX
         MOV ECX,EDI
         StoQD EDI
         SUB EDI,ECX
         BufferStore [%StmSlBuf],ECX,EDI
         MOV EAX,[EBX+STM.Program]
         JNSt [EAX+PGM.Status],pgmLastPass,.94:
         Invoke LstSet::,ECX,EDI
    .94: Invoke VarAssign::,EBX,[%StmSlBuf]
    .95: Invoke EaBufferRelease::,[%StmSlBuf]
    .99: EndProcedure PseudopcSETL

↑ PseudopcSETS Stm
  Pseudoinstruction %SETS handler.
Manual
  %SETC
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  EaBufferRelease EaBufferReserve LstSet StmCheckFields VarAssign VarCheckId VarExpand VarParseName
Tested by
  t2861

    PseudopcSETS Procedure Stm
    StmSsBuf LocalVar                                ; Temporary ^buffer.
    StmSsDec LocalVar Size=20                        ; Decadic value storage.
         MOV EBX,[%Stm]
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.99:
         Invoke StmCheckFields::, EBX, '1010'
         JC .99:
         Invoke VarCheckId::,[EBX+STM.LabelPtr],[EBX+STM.LabelSize]
         JC .99:
         Invoke EaBufferReserve::, PseudopcSETS
         MOV [%StmSsBuf],EAX
         BufferRetrieve [EBX+STM.OrdBuffer]
         MOV ECX,[ESI+4]
         MOV ESI,[ESI]                               ; ESI,ECX should be unexpanded %variable name.
         LEA EDX,[ESI+ECX]
         PUSH ESI
           Invoke VarParseName::,ESI,EDX
         POP ESI
         Msg cc=C,'7841'                             ; %%SETS and %%SETL expect %%variable name as the only operand.
         JC .95:
         Invoke VarExpand::,ESI,EDX,[%StmSsBuf],-1
         ; EAX= is pointer behind the parsed %variable name and its suboperations.
         BufferRetrieve [%StmSsBuf]
         BufferClear [%StmSsBuf]
         LEA EDI,[%StmSsDec]
         MOV EAX,ECX ; ValueSize
         SUB EDX,EDX
         MOV ECX,EDI
         StoQD EDI
         SUB EDI,ECX
         BufferStore [%StmSsBuf],ECX,EDI
         MOV EAX,[EBX+STM.Program]
         JNSt [EAX+PGM.Status],pgmLastPass,.94:
         Invoke LstSet::,ECX,EDI
    .94: Invoke VarAssign::,EBX,[%StmSsBuf]
    .95: Invoke EaBufferRelease::,[%StmSsBuf]
    .99: EndProcedure PseudopcSETS

↑ PseudopcSETX Stm
  Pseudoinstruction %SETX handler.
Manual
  %SETX
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  EaBufferRelease EaBufferReserve LstSet StmCheckFields VarAssign
Tested by
  t2881

    PseudopcSETX Procedure Stm
    StmSxBuf LocalVar ; Temporary ^buffer for label name.
         MOV EBX,[%Stm]
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.99:
         Invoke StmCheckFields::, EBX, '10**'
         JC .99:
         Invoke EaBufferReserve::,PseudopcSETX
         MOV [%StmSxBuf],EAX
         MOV EDX,EAX
         ; %SETX will concatenate ordinal and keyword operands, separated with comma.
         BufferRetrieve [EBX+STM.OrdBuffer]
         JECXZ .30:
    .10: ; ESI points to Ptr,Size of ordinal.
         BufferStore EDX,[ESI],[ESI+4]
         BufferStore EDX, =B',',1
         ADD ESI,8
         SUB ECX,8
         JA .10:
    .30: BufferRetrieve [EBX+STM.KeyBuffer]
         JECXZ .50:
    .40: BufferStore EDX,[ESI],[ESI+4]
         BufferStore EDX,=B'=',1
         BufferStore EDX,[ESI+8],[ESI+12]
         BufferStore EDX,=B',',1
         ADD ESI,16
         SUB ECX,16
         JG .40:
    .50: BufferDecrement EDX                         ; Omit the last comma, if at least one was stored.
         Invoke VarAssign::,EBX,EDX                  ; Value of %variable is in buffer EDX.
         MOV EAX,[EBX+STM.Program]
         JNSt [EAX+PGM.Status],pgmLastPass,.90:
         BufferRetrieve EDX
         Invoke LstSet::,ESI,ECX
    .90: Invoke EaBufferRelease::,[%StmSxBuf]
    .99:EndProcedure PseudopcSETX

↑ PseudopcWHILE Stm
  Pseudoinstruction %WHILE handler.
Manual
  %WHILE
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  Ctx1stRepeat CtxCreate CtxExpansionNrUpdate ExpEvalBoolOp1 LstBoolean StmCheckFields
Tested by
  t2700 t2701 t2702

    PseudopcWHILE Procedure Stm
         MOV EBX,[%Stm]
         StackPeekLast [Src.CtxStack::]
         JC .90:
         JNSt [EAX+CTX.Status],ctxWHILE,.30:
         MOV EDI,EAX ; ^CTX WHILE
         MOV EAX,[EDI+CTX.LinePtr]
         CMP EAX,[EBX+STM.LinePtr]
         JE .50: ; Do not push new ctxWHILE if %WHILE block continues expansion.
     .30:; New context will be created.
         Invoke StmCheckFields::,EBX,"?0?0"
         JC .90:
         Invoke Ctx1stRepeat:: ; Returns EAX=ctx1stRepeat only if all repeating contexts have it too.
         MOV ECX,ctxWHILE+ctxExpandable+ctxRepeat+ctxExpansion
         OR ECX,EAX ; Incorporate ctx1stRepeat.
         StackPush [Src.CtxStack::],0
         MOV EDI,EAX
         Invoke CtxCreate::,EDI,ECX,EBX
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.70:
     .50:Invoke ExpEvalBoolOp1::,EBX
         Invoke LstBoolean::
         JBE .70: ; Jump if FALSE - %WHILE block is ending.
         Invoke CtxExpansionNrUpdate::,EDI,EBX
         JNC .90:
    .70: SetSt [EDI+CTX.Status],ctxNoEmit+ctxExited
    .90:EndProcedure PseudopcWHILE

↑ PseudopcEXITWHILE Stm
  Pseudoinstruction %EXITWHILE handler.
Manual
  %EXITWHILE
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxFind StmCheckFields
Tested by
  t2702

    PseudopcEXITWHILE Procedure Stm
         MOV EBX,[%Stm]
         SetSt [Src.Lst.Status::],lstNoData
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90:
         JNSt [EBX+STM.CtxStatusAll],ctx1stRepeat,.30:
         Invoke StmCheckFields::,EBX,"00?0"
    .30: Invoke CtxFind::, ctxWHILE,EBX
         JNC .50:
         JNSt [EBX+STM.CtxStatusAll],ctx1stRepeat,.90:
         Msg '7120',Dict_PseudopcEXITWHILE:: ; Wrong nesting, unexpected !1S.
         JMP .90:
    .50: JZ .80:
         JNSt [EBX+STM.CtxStatusAll],ctx1stRepeat,.80:
         Msg '7110',Dict_PseudopcEXITWHILE::,EAX ; Wrong nesting, expected "!1S !2S".
    .80: SetSt [EAX+CTX.Status],ctxNoEmit+ctxExited ; Do not emit until %ENDWHILE.
    .90:EndProcedure PseudopcEXITWHILE

↑ PseudopcENDWHILE Stm
  Pseudoinstruction %ENDWHILE handler.
Manual
  %ENDWHILE
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxDiscard CtxFind StmCheckFields
Tested by
  t2700 t2701 t2702

    PseudopcENDWHILE Procedure Stm
         MOV EBX,[%Stm]
         SetSt [Src.Lst.Status::],lstNoData
         Invoke CtxFind::,ctxWHILE,EBX
         Msg cc=C,'7120',Dict_PseudopcENDWHILE:: ; Wrong nesting, unexpected !1S.
         JC .90:
         JE .20: ; If blockId matched.
         JNSt [EBX+STM.CtxStatusAll],ctx1stRepeat,.20:
         Msg '7110',Dict_PseudopcENDWHILE::,EAX ; Wrong nesting, expected "!1S !2S".
    .20: MOV EDI,EAX ; ^CTX WHILE.
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.70: ; Expansion of %WHILE block is ending.
         ; %WHILE condition was TRUE, leave context EDI on stack and goto %WHILE statement.
         RstSt [EDI+CTX.Status],ctx1stRepeat ; Do not list further expansions.
         MOV ECX,[EDI+CTX.LinePtr]
         MOV EDX,[EDI+CTX.ChunkPtr]
         MOV [EBX+STM.LineNext],ECX ; Continue expansion, go back to %WHILE statement.
         MOV [EBX+STM.ChunkNext],EDX
         JMPS .90:
     .70:JNSt [EBX+STM.CtxStatusAll],ctx1stRepeat,.80:
         Invoke StmCheckFields::,EBX,"00?0"
     .80:Invoke CtxDiscard::,EDI,EBX
    .90:EndProcedure PseudopcENDWHILE

↑ PseudoPROC Stm
  Pseudoinstruction PROC handler.
Manual
  PROC
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxCreate ExpAlign SssCheckPurpose SssGetSegm StmCheckFields StmGetIiModifiers SymCreate

    PseudoPROC Procedure Stm
    Ii   LocalVar Size=SIZE#II
         ClearLocalVar
         MOV EBX,[%Stm]
         LEA EDI,[%Ii]
         IiAllowModifier DIST
         Invoke StmGetIiModifiers::,EBX,EDI
         MOV EAX,[EDI+II.MfgExplicit]
         SUB EDI,EDI                                 ; Pointer to an object if context is created.
         JNSt EAX,iiMfgNESTING_OFF,.10:
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90:   ; In noemitting status without nesting-check do not push context.
         JMPS .15:                                   ; Emit ctxPROC with supressed nesting check.
     .10:MOV ECX,ctxNoEmit+ctxPROC+ctxNamespace
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.80:   ; In noemitting status with standard nesting-check only push ctxPROC.
     .15:; Emit.
         StmInStruc EBX,.90:                         ; Do not allow this statement in a structure definition.
         Invoke StmCheckFields::,EBX,"100*"
         ; Select code section.
         MOV EDI,[EBX+STM.Section]
         TEST EDI
         JZ .20:
         JSt [EDI+SSS.Purpose],sssPurposeCODE,.30:   ; If no need to change the current section.
         JNSt [Ea::+EA.Eaopt+EAOPT.Status],eaoptAUTOSEGMENT, .25:
                                                     ; AUTOSEGMENT is enabled, switch to the code section.
    .20: Invoke SssGetSegm::, [EBX+STM.Program], sssPurposeCODE; Find the  first code section of this program.
         JC .90:
         MOV [EBX+STM.Section],EAX
         MOV EDI,EAX
    .25: Invoke SssCheckPurpose::,EDI,sssPurposeCODE ; Warn if a wrong section was chosen.
    .30: ; Set symbol properties.
         MOV EAX,[EDI+SSS.OrgLow]
         MOV EDX,[EDI+SSS.OrgHigh]
         MOV [EBX+STM.OffsetLow],EAX
         MOV [EBX+STM.OffsetHigh],EDX
    .40: LEA ECX,[%Ii]
         MOV EAX,stmProc
         JNSt [ECX+II.MfgExplicit],iiMfgDIST_FAR,.45:
         OR  EAX,stmFar
    .45: JNSt [ECX+II.MfgExplicit],iiMfgDIST_NEAR,.50:
         OR  EAX,stmNear
    .50: JSt EAX,stmNear|stmFar,.60:
         MOV ECX,[EBX+STM.Program]                   ; If PROC DIST= is not explicitly specified, query PROGRAM MODEL=.
         JECXZ .60:
         JSt [ECX+PGM.Pgmopt+PGMOPT.Status],pgmoptMEDIUM|pgmoptLARGE|pgmoptHUGE,.55:
         OR EAX,stmNear
         JMP .60:
    .55: OR  EAX,stmFar
    .60: SetSt [EBX+STM.Status],EAX
         LEA ECX,[%Ii]                               ; Set alignment.
         Invoke ExpAlign::,[EBX+STM.OffsetLow],[ECX+II.Align],0
         MOV [EBX+STM.AlignBytes],ECX
         ADD [EBX+STM.OffsetLow],ECX
         ADCD [EBX+STM.OffsetHigh],0
         MOVB [EBX+STM.Status],'A'                   ; Create the symbol with proc name.
         MOV EAX,stmLabelIsPublic
         AND EAX,[EBX+STM.Status]
         OR  EAX,symDefined
         Invoke SymCreate::,EAX,[EBX+STM.LabelPtr],[EBX+STM.LabelSize],EBX
         MOV EDI,EAX                                 ; PROC symbol.
    .70: MOV ECX,ctxPROC+ctxNamespace
         LEA EDX,[%Ii]
         JNSt [EDX+II.MfgExplicit],iiMfgNESTING_OFF,.80:
         OR ECX,ctxNestingOff
    .80: StackPush [Src.CtxStack::],0
         MOV EDX,EAX                                 ; Create a new PROC context.
         Invoke CtxCreate::,EDX,ECX,EBX
         MOV [EAX+CTX.ObjPtr],EDI
    .90:EndProcedure PseudoPROC

↑ PseudoENDPROC Stm
  Pseudoinstruction ENDPROC handler.
Manual
  ENDPROC
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxDiscard CtxFind StmCheckFields StmGetIiModifiers SymCreate
Tested by
  t1210

    PseudoENDPROC Procedure Stm
    Ii  LocalVar Size=SIZE#II                        ; Required by StmGetIiModifiers.
        ClearLocalVar
        MOV EBX,[%Stm]
        LEA EDI,[%Ii]
        Invoke StmGetIiModifiers::,EBX,EDI
        StmInStruc EBX,.90:                          ; Do not allow this statement in a structure definition.
        Invoke StmCheckFields::,EBX,"?0?*"           ; Allow label field and one ordinal.
        Invoke CtxFind::,ctxPROC,EBX                 ; Check context.
        MOV ECX,EAX                                  ; ^CTX or NULL if CF=1.
        LAHF                                         ; Store flags to AH.
        JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.80:    ; In noemitting status just pop the context, do not report errors.
        ; Emit.
        SAHF                                         ; Restore the result of CtxFind to Eflags.
        Msg cc=C,'7120',Dict_PseudoENDPROC::         ; Wrong nesting, unexpected !1S.
        JC .90:
        JZ .30:                                      ; Jump if block ids match.
        JSt [EDI+II.MfgExplicit],iiMfgNESTING_OFF,.30:; Ignore when ENDPROC NESTINGCHECK=DISABLED.
        Msg '7110',Dict_PseudoENDPROC::,ECX          ; Wrong nesting, expected "!1S !2S".
    .30:MOV ESI,[ECX+CTX.BlockSect]                  ; Section might have been changed inside PROC..ENDP, restore it from context ECX.
        MOV EAX,[ESI+SSS.OrgLow]
        MOV EDX,[ESI+SSS.OrgHigh]
        MOV [EBX+STM.OffsetLow],EAX
        MOV [EBX+STM.OffsetHigh],EDX
        MOV [EBX+STM.Section],ESI
        MOV EAX,[EBX+STM.Program]
        MOV [EAX+PGM.CurrentSect],ESI
        JNSt [EBX+STM.Status],stmLabelPresent,.50:
        MOV EAX,symDefined                           ; The statement ENDPPROC may have a label and ordinal operand.
        JNSt [EBX+STM.Status],stmLabelIsPublic,.40:
        OR EAX,symGlobalRef
    .40:Invoke SymCreate::,EAX,[EBX+STM.LabelPtr],[EBX+STM.LabelSize],EBX
    .50:; Update size of the symbol defined by the corresponding PROC. It will be the size of PROC..ENDP code.
        MOV EDI,[ECX+CTX.ObjPtr]                     ; EDI=^SYM defined by PROC.
        TEST EDI
        JZ .90:
        MOV EAX,[EBX+STM.OffsetLow]
        MOV EDX,[EBX+STM.OffsetHigh]
        SUB EAX,[EDI+SYM.OffsetLow]
        SBB EDX,[EDI+SYM.OffsetHigh]
        Msg cc=B,'7167',EDI                          ; Size of procedure "!1S" exceeds 2 GB.
        CMP EAX,[EDI+SYM.Size]
        MOV [EDI+SYM.Size],EAX
        JE .80:
        RstSt [EDI+SYM.Status],symFixed
    .80:JECXZ .90:
        Invoke CtxDiscard::,ECX,EBX
    .90:EndProcedure PseudoENDPROC

↑ PseudoPROC1 Stm
  Pseudoinstruction PROC1 handler.
Manual
  PROC1
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxCreate EaBufferRelease EaBufferReserve ExpAlign SssCreate@RT StmCheckFields StmGetIiModifiers SymCreate SymDelocalName SymFindByName
Tested by
  t1717

    PseudoPROC1 Procedure Stm
    PreviousSect LocalVar                            ; ^SSS on PROC1 entry, must be restored after ENDPROC1.
    Ii  LocalVar Size=SIZE#II
        ClearLocalVar
        MOV EBX,[%Stm]
        MOV EAX,[EBX+STM.Section]
        LEA EDI,[%Ii]
        MOV [%PreviousSect],EAX
        IiAllowModifier DIST
        Invoke StmGetIiModifiers::,EBX,EDI
        MOV EAX,[EDI+II.MfgExplicit]
        SUB EDI,EDI                                  ; Pointer to the object if context is created.
        JNSt EAX,iiMfgNESTING_OFF,.10:
        JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90:    ; In noemitting status without nesting-check do not push context.
        JMPS .20:                                    ; Emit ctxPROC1 with supressed nesting check.
    .10:MOV ECX,ctxNoEmit+ctxPROC1+ctxNamespace
        JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.70:    ; In noemitting status with standard nesting-check only push ctxPROC1.
    .20:StmInStruc EBX,.90:                          ; Emit. Do not allow this statement in a structure definition.
        Invoke StmCheckFields::,EBX,"100*"
        Invoke EaBufferReserve::,PseudoPROC1         ; If PROC1 symbol was already created in this pass, the block will not emit.
        Invoke SymDelocalName::,[EBX+STM.LabelPtr],[EBX+STM.LabelSize],EAX,memberDelocal
        BufferRetrieve EAX
        Invoke EaBufferRelease::,EAX
        Invoke SymFindByName::,0,ESI,ECX,[EBX+STM.Program]
        JC .30:                                      ; When PROC1 statement was encounterred for the first time.
        MOV ECX,ctxNoEmit+ctxPROC1+ctxNamespace
        JSt [EAX+SYM.Status],symDefInPass|symExtern,.70: ; If PROC1 was already declared or it is external, do not emit.
    .30:Invoke SssCreate@RT::,[%PreviousSect],EBX    ; Create or update PROC1 symbol. Select CODE runtime section.
        MOV [EBX+STM.Section],EAX                    ; Switch to the runtime section.
        MOV EDX,[EAX+SSS.OrgHigh]                    ; Set symbol properties.
        MOV EAX,[EAX+SSS.OrgLow]
        MOV [EBX+STM.OffsetHigh],EDX
        MOV [EBX+STM.OffsetLow],EAX
        LEA ECX,[%Ii]
        MOV EAX,stmProc+stm1
        JNSt [ECX+II.MfgExplicit],iiMfgDIST_FAR,.40:
        OR  EAX,stmFar
    .40:JNSt [ECX+II.MfgExplicit],iiMfgDIST_NEAR,.45:
        OR EAX,stmNear
    .45:JSt EAX,stmNear|stmFar,.55:
        MOV ECX,[EBX+STM.Program]                    ; If PROC DIST= is not explicitly specified, query PROGRAM MODEL=.
        JECXZ .55:
        JSt [ECX+PGM.Pgmopt+PGMOPT.Status],pgmoptMEDIUM|pgmoptLARGE|pgmoptHUGE,.50:
        OR EAX,stmNear
        JMP .55:
    .50:OR EAX,stmFar
    .55:SetSt [EBX+STM.Status],EAX
    .60:SetSt [EBX+STM.Status],stmProc
        LEA ECX,[%Ii]                                ; Set alignment.
        Invoke ExpAlign::,[EBX+STM.OffsetLow],[ECX+II.Align],0
        MOV [EBX+STM.AlignBytes],ECX
        ADD [EBX+STM.OffsetLow],ECX
        ADCD [EBX+STM.OffsetHigh],0
        MOVB [EBX+STM.Status],'A'                    ; Create the symbol with proc1 name.
        MOV EAX,stmLabelIsPublic
        AND EAX,[EBX+STM.Status]
        OR  EAX,symDefined
        Invoke SymCreate::,EAX,[EBX+STM.LabelPtr],[EBX+STM.LabelSize],EBX
        MOV EDI,EAX                                  ; PROC1 symbol.
        MOV ECX,ctxPROC1+ctxNamespace
    .70:LEA EDX,[%Ii]
        JNSt [EDX+II.MfgExplicit],iiMfgNESTING_OFF,.80:
        OR ECX,ctxNestingOff
    .80:StackPush [Src.CtxStack::],0
        MOV EDX,EAX                                  ; Create new PROC1 context.
        Invoke CtxCreate::,EDX,ECX,EBX
        MOV ECX,[%PreviousSect]
        MOV [EDX+CTX.ObjPtr],EDI
        MOV [EDX+CTX.PreviousSect],ECX
    .90:EndProcedure PseudoPROC1

↑ PseudoENDPROC1 Stm
  Pseudoinstruction ENDPROC1 handler.
Manual
  ENDPROC1
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxDiscard CtxFind PgmGetCurrent StmCheckFields StmGetIiModifiers SymCreate
Tested by
  t1717

    PseudoENDPROC1 Procedure Stm
    Ii  LocalVar Size=SIZE#II                        ; Required by StmGetIiModifiers.
        ClearLocalVar
        MOV EBX,[%Stm]
        LEA EDI,[%Ii]
        Invoke StmGetIiModifiers::,EBX,EDI
        StmInStruc EBX,.90:                          ; Do not allow this statement in a structure definition.
        Invoke StmCheckFields::,EBX,"?0?*"           ; Allow label field and one ordinal.
        Invoke CtxFind::,ctxPROC1,EBX                ; Check context.
        MOV ECX,EAX                                  ; ^CTX or NULL if CF=1.
        LAHF                                         ; Store flags to AH.
        JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.70:    ; In noemitting status just pop the context, do not report errors.
        ; Emit.
        SAHF                                         ; Restore the result of CtxFind to Eflags.
        Msg cc=C,'7120',Dict_PseudoENDPROC1::        ; Wrong nesting, unexpected !1S.
        JC .90:
        JZ .30:                                      ; Jump if block ids match.
        JSt [EDI+II.MfgExplicit],iiMfgNESTING_OFF,.30:; Ignore when ENDPROC NESTINGCHECK=DISABLED.
        Msg '7110',Dict_PseudoENDPROC1::,ECX         ; Wrong nesting, expected "!1S !2S".
    .30:MOV ESI,[ECX+CTX.BlockSect]                  ; If @RTx section was changed inside PROC1..ENDP1,
        MOV EAX,[ESI+SSS.OrgLow]                     ;  restore it temporarily to match [@RT*] chosen for PROC1 statement.
        MOV EDX,[ESI+SSS.OrgHigh]
        MOV [EBX+STM.Section],ESI
        MOV [EBX+STM.OffsetLow],EAX
        MOV [EBX+STM.OffsetHigh],EDX
        JNSt [EBX+STM.Status],stmLabelPresent,.50:
        MOV EAX,symDefined                           ; The statement ENDPPROC1 may have a label.
        JNSt [EBX+STM.Status],stmLabelIsPublic,.40:
        OR EAX,symGlobalRef
    .40:Invoke SymCreate::,EAX,[EBX+STM.LabelPtr],[EBX+STM.LabelSize],EBX
    .50:; Update size of the symbol defined with the corresponding PROC1. It will be the size of PROC1..ENDP1 code.
        MOV EDI,[ECX+CTX.ObjPtr]                     ; EDI=^SYM defined by PROC1.
        MOV EAX,[EBX+STM.OffsetLow]
        MOV EDX,[EBX+STM.OffsetHigh]
        SUB EAX,[EDI+SYM.OffsetLow]
        SBB EDX,[EDI+SYM.OffsetHigh]
        Msg cc=B,'7167',EDI                          ; Size of procedure "!1S" exceeds 2 GB.
        CMP EAX,[EDI+SYM.Size]
        MOV [EDI+SYM.Size],EAX
        JE .70:
        RstSt [EDI+SYM.Status],symFixed
    .70:MOV ESI,[ECX+CTX.PreviousSect]               ; Restore the section which preceeded PROC1 statement.
        Invoke PgmGetCurrent::
        JC .80:
        MOV [EAX+PGM.CurrentSect],ESI
        SetSt [EBX+STM.Flags],stmtKeepSect           ; Keep PGM.CurrentSect not updated from STM.Section.
    .80:JECXZ .90:
        Invoke CtxDiscard::,ECX,EBX
    .90:EndProcedure PseudoENDPROC1

↑ PseudoPROGRAM Stm
  Pseudoinstruction PROGRAM handler.
Manual
  PROGRAM
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxCreate CtxFind PassCreate PgmCreateProgram PgmParameters PgmoptCheck PgmoptSetDefaults SssCreateImplicit StmCheckFields

    PseudoPROGRAM Procedure Stm
         MOV EBX,[%Stm]
         SetSt [Src.Lst.Status::],lstNoData
         MOVD [Src.Lst.Section::],0
         JNSt [EBX+STM.CtxStatusAll],ctxNoEmit,.20:
    .10: ; PROGRAM statement in nonemitting state will only push nonemitting ctxPROGRAM. PGM is not created.
         StackPush [Src.CtxStack::],0
         Invoke CtxCreate::,EAX,ctxPROGRAM+ctxNamespace+ctxNoEmit,EBX
         JMP .90:                                    ; Do nothing else in nonemitting state.
    .20: Invoke CtxFind::,ctxPROGRAM,0               ; Return parent program context in EAX.
         JC .40:                                     ; Skip if the statement is envelope PROGRAM (no other program context is on CtxStack).
         MOV EDI,EAX                                 ; Current program context.
         JSt [EDI+CTX.Status],ctxPgmReturned,.70:    ; If arrived to PROGRAM from ENDPROGRAM (the next pass begins).
         ; Otherwise arrived here in normal statements flow. Start to assemble the new program if parent is in the final pass.
         MOV ECX,[EDI+CTX.ObjPtr]                    ; Get Pgm object from context stack.
         JECXZ .10:
         JNSt [ECX+PGM.Status],pgmLastPass,.10:      ; If parent is not in final pass, skip the entire PROGRAM/ENDPROGRAM block.
         ; Entered the statement PROGRAM in emitting state, parent program is in its final pass.
    .40: ; Arrived here in normal stream of statements. A new program is created.
         Invoke StmCheckFields::,EBX,"100*"
         JC .90:
         StmInStruc EBX,.90:                         ; Do not allow this statement in a structure definition.
         StackPush [Src.CtxStack::],0                ; Allocate room for the new program context.
         MOV EDI,EAX                                 ; EDI=New program context.
         Invoke CtxCreate::,EDI,ctxPROGRAM+ctxNamespace,EBX
         Invoke PgmCreateProgram::,EBX               ; New program starts, its ptr is returned in EAX.
         MOV ECX,EAX                                 ; ECX=^PGM.
         MOV [EDI+CTX.ObjPtr],EAX
     .70:RstSt [EDI+CTX.Status],ctxPgmReturned
         JNSt [ECX+PGM.Status],pgmEnvelope,.80:
         JNSt [ECX+PGM.Status],pgmEnvelDirty,.75:
         SetSt [Src.Lst.Status::],lstEnvelope+lstListOn
         JMP .80:
     .75:SetSt [Src.Lst.Status::],lstEnvelope+lstNoList
     .80:Invoke PgmParameters::,ECX,EBX              ; Assemble PROGRAM keywords again, report errors.
         LEA EAX,[ECX+PGM.Pgmopt]
         Invoke PgmoptSetDefaults::,EAX
         Invoke PgmoptCheck::,ECX
         CMPD [ECX+PGM.PassNr],1
         JA .85:
         Invoke SssCreateImplicit::,ECX              ; Only when PROGRAM was encountered in pass 1.
    .85: Invoke PassCreate::,ECX
    .90: EndProcedure PseudoPROGRAM

↑ PseudoENDPROGRAM Stm
  Pseudoinstruction ENDPROGRAM handler.
Manual
  ENDPROGRAM
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxDiscard CtxFind CtxPeek MacListMerge PassDestroy PassInspect PgmCheckDirty PgmDestroy PgmLinkSections PgmListLiterals StmCheckFields VarListMerge

    PseudoENDPROGRAM Procedure Stm
         MOV EBX,[%Stm]
         SetSt [Src.Lst.Status::],lstNoData
         Invoke CtxFind::,ctxPROGRAM,EBX
         Msg cc=C,'7120',Dict_PseudoENDPROGRAM::      ; Wrong nesting, unexpected !1S.
         JC .90:
         Msg cc=NE,'7110',Dict_PseudoENDPROGRAM::,EAX ; Wrong nesting, expected "!1S !2S".
         MOV ESI,EAX                                  ; ^CTX PROGRAM.
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.80:    ; In noemitting status the block terminates, context is popped.
         ; ENDPROGRAM in emitting state will terminate current pass and redirect assembly
         ;     back to the corresponding PROGRAM statement, unless this pass was the last.
         Invoke StmCheckFields::,EBX,"00?0"
         StmInStruc EBX,.90:                          ; Do not allow this statement in a structure definition.
         MOVD [EBX+STM.Section],0                     ; Prevent listing to show the last [section] from previous pass.
         MOV EDI,[ESI+CTX.ObjPtr]                     ; EDI=^PGM.
         TEST EDI
         JZ .90:
         MOVD [EDI+PGM.CurrentSect],0                 ; Prevent listing to show the last [section] from previous pass.
         JNSt [EDI+PGM.Status],pgmEnvelope,.40:
         Invoke PgmCheckDirty::,EDI
         JNC .30:                                     ; If envelope is not dirty, turn the listing of ENDPROGRAM statement off.
         SetSt [EDI+PGM.Status],pgmEnvelDirty
         SetSt [Src.Lst.Status::],lstEnvelope+lstListOn
         JMP .40:
    .30: SetSt [Src.Lst.Status::],lstEnvelope+lstNoList
    .40: Invoke PassInspect::,EDI                     ; Return CF if at least one more pass is due. Set pgmLastPass if it will be the last one.
         JNC .50:                                     ; Skip when no more passes are needed.
         JNSt [EDI+PGM.Status],pgmLastPass,.45:
         SetSt [EDI+PGM.Status],pgmLastJustSet        ; Tell SrcAssemble to skip this statement (ENDPROGRAM) in listing.
    .45: Invoke PassDestroy::,EDI                     ; Another pass is required. It may be the last.
         BufferClear [EBX+STM.MsgBuffer]              ; Erase messages gathered in nonlisting pass.
         MOVB [MsgPgmStatus::],0                      ; Cancel possible msg suppressing from nonlisted error messages from previous pass.
         StackPeekLast [Src.CtxStack::]
         JNSt [EAX+CTX.Status],ctxPROGRAM,.70:        ; Abort the program if context mismatch.
         MOV ECX,[ESI+CTX.LinePtr]                    ; Redirect assembly progress back to the statement PROGRAM.
         MOV EDX,[ESI+CTX.ChunkPtr]
         MOV [EBX+STM.LineNext],ECX                   ; Continue assembly with PROGRAM statement,
         MOV [EBX+STM.ChunkNext],EDX                  ;   which will be skipped due to ctxPgmPassed.
         SetSt [ESI+CTX.Status],ctxPgmPassed+ctxPgmReturned ; Mark the program as passed, but do not destroy it. Leave it on stack.
         JMP .90:
    .50: ; The last pass has just ended. Before destroying its pool, %variables and macros
         ;   defined in this program EDI will be merged to the parent program (they are visible in the entire source).
         Invoke CtxPeek::,ctxPROGRAM,ESI              ; Find parent program above context of this program.
         JC .60:                                      ; Skip merging if no parent exists, i.e. EDI is an envelope program.
         MOV ECX,[EAX+CTX.ObjPtr]
         JECXZ .60:
         Invoke VarListMerge::,[ECX+PGM.PassPtr],[EDI+PGM.PassPtr]
         Invoke MacListMerge::,[ECX+PGM.PassPtr],[EDI+PGM.PassPtr]
    .60: JNSt [EDI+PGM.Pgmopt.Status],pgmoptLISTLITERALS,.70:
         Invoke PgmListLiterals::,EDI
    .70: SUB EAX,EAX
         MOV [EBX+STM.Section],EAX
         Invoke PassDestroy::,EDI
         CMP EAX,[EDI+PGM.MemPeakPass]                ; EAX=memory allocated by the pass.
         JNA .75:
         MOV [EDI+PGM.MemPeakPass],EAX
    .75: Invoke PgmLinkSections::,EDI
         Invoke PgmDestroy::, EDI,EBX                 ; Combine and link modules and store the output file.
         CMP EAX,[Src.MemPeakPgm::]
         JNA .80:
         MOV [Src.MemPeakPgm::],EAX
    .80: Invoke CtxDiscard::,ESI,EBX                  ; Continue assembly with the statement which follows ENDPROGRAM.
         Invoke CtxPeek::,ctxPROGRAM,0                ; Find the parent program, if exists.
         JC .90:
         TEST EAX
         JZ .90:
         MOV ECX,[EAX+CTX.ObjPtr]
         JECXZ .90:
         MOV [EBX+STM.Program],ECX                    ; Program was assembled and written. Continue with its parent.
    .90:EndProcedure PseudoENDPROGRAM

↑ PseudoSEGMENT Stm
  Pseudoinstruction SEGMENT handler.
Manual
  SEGMENT
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  DictLookup EaBufferRelease EaBufferReserve ExpEvalNum ExpParseAlignment IiCpuToKeys SssCheckDirty SssCreateSe SssFindByName SssGuessPurpose StmCheckFields

    PseudoSEGMENT Procedure Stm
    SegmPtr LocalVar
         MOV EBX,[%Stm]
         StmInStruc EBX,.90:                         ; Do not allow this statement in a structure definition.
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.99:
         Invoke StmCheckFields::,EBX,"100*"
         JC .90:
         ; Check segment name. Label field must be in braces [].
         MOV ECX,[EBX+STM.LabelSize]
         MOV ESI,[EBX+STM.LabelPtr]
         JECXZ .E6815:
         CMPB [ESI],'['
         JE .05:
    .E7831:Msg '7831',EBX                             ; Segment name "!1S" must be in braces [].
         JMP .90:
    .E6815:Msg '6815'                                 ; Segment name in [] is expected in the label field of SEGMENT definition.
         JMP .90:
    .05: CMPB [ESI+ECX-1],']'
         JNE .E7831:
         INC ESI
         SUB ECX,2
         StripSpaces ESI,ECX
         JECXZ .E6815:
         MOV EDX,[EBX+STM.Program]
         ; AUTOSEGMENT is silently switched OFF by any statement which changes|declares section|segment.
         RstSt [Ea.Eaopt.Status::],eaoptAUTOSEGMENT
         Invoke SssFindByName::, sssTypeMask,0,ESI,ECX,0 ; Find any older segment, section or structure with this name.
         MOV EDI,EAX
         JC .20:                                      ; Jump if the name is free (not found).
         ; SSS object EDI already exist in the list. This may be OK if redeclaring implicit virgin segment.
         JSt [EDI+SSS.Status],sssImplicit,.10:
         JNSt [EDI+SSS.Status],sssDefinedInPass, .30: ; OK when it was declared in previous pass and not in this one.
    .E7833:Msg '7833',EDI,[EDI+SSS.LinePtr]           ; Segment, section or structure [!1S] was already declared in !2@.
         JMP .90:
    .E7835:Msg '7835',EDI,PgmStatus=pgmLastPass       ; Implicit segment [!1S] cannot be redeclared, it is not empty.
         JMP .90:
    .10: Invoke SssCheckDirty::,EDI,EDX               ; Implicit segment may be redeclared only if it was not used before.
         JC .E7835:
         ; Virgin implicit segment EDI is redeclared. ; EBX=^STM, EDX=^PGM, EDI=^SSS.
         MOV EAX,[EBX+STM.LinePtr]
         MOV [EDI+SSS.LinePtr],EAX
         RstSt [EDI+SSS.Status],sssImplicit
         JMP .30:
    .20: MOV EDI,[EDX+PGM.Pgmopt.Status]
         AND EDI,pgmoptWidthMask                      ; pgmoptWidth flags have assigned same values as sssWidth.
         OR EDI,sssSegment+sssSection+sssPublic+sssDefinedInPass ; Default new segment status.
         Invoke SssCreateSe::,EBX,0,ESI,ECX,EDI,0,16
         MOV EDI,EAX
    .30: SetSt [EDI+SSS.Status],sssDefinedInPass
         MOV [EBX+STM.Section],EDI ; Make the just created section the current section.
         ; Keyword operands of SEGMENT statement may update its properties.
         BufferRetrieve [EBX+STM.KeyBuffer]
         LEA EDX,[ESI+ECX]
    .50: CMP ESI,EDX ; Process all keyword parameters.
         JNB .90:
         MOV ECX,ESI                                 ; Prepare ECX=pointer to key name for the case of E7800.
         LODSD                                       ; Key NamePtr.
         MOV EDI,EAX
         LODSD                                       ; Key NameSize.
         Invoke DictLookup::, DictSegmentKeys::, EDI,EAX
         PUSH EAX
           LEA EAX,[EBX+STM.OperationPtr]
           Msg cc=C,'7800',EAX,ECX,DictSegmentKeys:: ; Unknown %1S keyword "!2S". Expected one of !3L.
         POP ECX                                     ; PseudoSEGMENT.Keyword handler.
         LODSD                                       ; Key ValuePtr.
         MOV EDI,EAX
         LODSD                                       ; Key ValueSize.
         JC .50:
         StripSpaces EDI,EAX
         JMP ECX                                     ; Key value handler.
         ; Segment key value handlers. Key value is in EDI,EAX. ESI is ptr behind 4*DWORD with key.
         ;  ESI,EDX,EBX,EBP must be preserved in value handlers.
    .Purpose:: ; Multiple purposes may be separated with '+' or '|', e.g.  "PURPOSE=Data| Bss"
         PUSH EDX,ESI
          MOV ESI,EDI ; Value start.
          LEA EDX,[EDI+EAX] ; Value end.
          MOV EDI,[EBX+STM.Section]
          MOVD [EDI+SSS.Purpose],0                   ; Remove old purposes first.
    .P1:  CMP ESI,EDX                                ; Simplified purpose value parsing begins.
          JNB .P9:
          LODSB
          ExpClassify AL
          CMP AH,expWhiteSpace
          JE .P1:
          CMP AL,'+'
          JE .P1:
          CMP AL,'|'
          JE .P1:
          CMP AH,expLetter
          Msg cc=NE,'6531',EAX ; Illegal character "!1Z" in purpose specification. Expected "PURPOSE=DATA|CODE|BSS"
          JNE .P9:
          LEA EDI,[ESI-1]                             ; Start of purpose name.
    .P2:  CMP ESI,EDX
          JNB .P3:
          LODSB
          ExpClassify AL
          CMP AH,expLetter
          JE .P2:
          DEC ESI
    .P3:  MOV EAX,ESI
          SUB EAX,EDI
          Invoke DictLookup::, DictSegmentPurpose::, EDI,EAX
          JC .E7805:
          MOV EDI,[EBX+STM.Section]
          SetSt [EDI+SSS.Purpose],EAX
          JMP .P1:
    .E7805:
         POP ESI,EDX
         LEA EDI,[ESI-16]
         LEA ECX,[ESI-8]
         Msg '7805',EDI,ECX,DictSegmentPurpose::      ; Unknown %1S value "!2S". Expected one of !3L.
         JMP .50:
    .P9: POP ESI,EDX
         JMP .50:
    .Width::
         PUSH EDX
           Invoke ExpEvalNum::,EDI,EAX                ; Evaluates to EDX:EAX.
         POP EDX
         MOV ECX,sssWidth64
         CMP EAX,64
         JE .Width5:
         MOV ECX,sssWidth32
         CMP EAX,32
         JE .Width5:
         MOV ECX,sssWidth16
         CMP EAX,16
         Msg cc=NE,'6525',EAX                        ; Invalid width !1D, must be 16 or 32 or 64.
         JNE .50:
    .Width5: MOV EDI,[EBX+STM.Section]
         RstSt [EDI+SSS.Status],sssWidthMask
         SetSt [EDI+SSS.Status],ECX
         Dispatch ECX,sssWidth32,sssWidth16
         JSt [Ea.Eaopt.Machine::],iiCPU_X64,.50:
         PUSH ESI
           Invoke EaBufferReserve::,PseudoSEGMENT
           Invoke IiCpuToKeys::,iiCPU_X64,0,EAX
           BufferRetrieve EAX
           Invoke EaBufferRelease::,EAX
           PUSH ECX,ESI
            MOV EAX,ESP
            Msg '2340',EAX                            ; This instruction requires option EUROASM "!1S".
           POP ESI,ECX
         POP ESI
         JMP .50:
    .sssWidth32:
         JSt [Ea.Eaopt.Machine::],iiCPU_386,.50:
         PUSH ESI
           Invoke EaBufferReserve::,PseudoSEGMENT
           Invoke IiCpuToKeys::,iiCPU_386,0,EAX
           BufferRetrieve EAX
           Invoke EaBufferRelease::,EAX
           PUSH ECX,ESI
            MOV EAX,ESP
            Msg '2340',EAX                            ; This instruction requires option EUROASM "!1S".
           POP ESI,ECX
         POP ESI
    .sssWidth16:
         JMP .50:
    .Align::
         Invoke ExpParseAlignment::,EDI,EAX,-1
         JC .50:
         ; EAX is one of 0,1,2,4,8..512.
         MOV EDI,[EBX+STM.Section]
         MOV [EDI+SSS.Alignment],EAX
         JMP .50:
    .Combine::
         Invoke DictLookup::, DictSegmentCombine::, EDI,EAX
         LEA EDI,[ESI-16]
         LEA ECX,[ESI-8]
         Msg cc=C,'7805',EDI,ECX,DictSegmentCombine:: ; Unknown %1S value "!2S". Expected one of !3L.
         JC .50:
         MOV EDI,[EBX+STM.Section]
         RstSt [EDI+SSS.Status],sssCombineMask
         SetSt [EDI+SSS.Status],EAX
         JMP .50:
    .Class::
         MOV ECX,EAX
         StripSpaces EDI,ECX
         StripQuotes EDI,ECX
         StripApostrophes EDI,ECX
         PUSH ESI
          MOV ESI,[EBX+STM.Program]
          PoolStore [ESI+PGM.Pool],EDI,ECX
          JC .Cl8:
          MOV ESI,[EBX+STM.Section]
          MOV [ESI+SSS.ClassPtr],EAX
          MOV [ESI+SSS.ClassSize],ECX
    .Cl8:POP ESI
         JMP .50:
    .90: SetSt [Src.Lst.Status::],lstSectInline      ; Display [Segm] in dump column on the same line.
         MOVD [Src.Lst.Section::],0                  ; Force listing to display [Segment] in dump column.
         MOV EDI,[EBX+STM.Section]
         Invoke SssGuessPurpose::,EDI
         Msg cc=Z,'6530'                             ; Please specify SEGMENT PURPOSE= (combination of DATA|CODE|BSS).
    .99:EndProcedure PseudoSEGMENT

↑ PseudoGROUP Stm
  Pseudoinstruction GROUP handler.
Manual
  GROUP
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  SssCreateGroup SssCreateSe SssFindByName StmCheckFields SymCreateSe
Tested by
  t3018 t3019

    PseudoGROUP Procedure Stm
         MOV EBX,[%Stm]
         StmInStruc EBX,.90:                         ; Do not allow this statement in a structure definition.
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.99:
         Invoke StmCheckFields::,EBX,"10*0"
         JC .90:
         ; Check group name. Label field must be in braces [].
         MOV ESI,[EBX+STM.LabelPtr]
         MOV ECX,[EBX+STM.LabelSize]
         JECXZ .E6814:
         CMPB [ESI],'['
         JE .05:
    .E7831:Msg '7831',EBX                            ; Segment, group or section name "!1S" must be in braces [].
         JMP .90:
    .E6814:Msg '6814'                                ; Group name in [] is expected in the label field of GROUP definition.
         JMP .90:
    .05: CMPB [ESI+ECX-1],']'
         JNE .E7831:
         INC ESI
         SUB ECX,2
         StripSpaces ESI,ECX
         JECXZ .E6814:
         MOV EDX,[EBX+STM.Program]
         Invoke SssFindByName::, sssGroup,0,ESI,ECX,0; Find any older group with this name.
         MOV EDI,EAX
         JC .10:                                     ; If the name is unoccupied yet.
         ; Group EDI already exists in the list.
         JNSt [EDI+SSS.Status],sssDefinedInPass,.30: ; Skip W2931 if it was declared in previous pass.
    .W2931:Msg '2931',EDI,[EDI+SSS.LinePtr]          ; Updating group [!1S] previously declared in !2@.
         JMP .30:
    .E7838:Msg '7838',EAX                            ; [!1S] is not 16bit segment, it cannot be member of a group.
         JMP .80:
    .10: ; Create a new group with name in ESI,ECX.
         Invoke SssCreateGroup::,EBX,ESI,ECX,sssGroup,0
         Invoke SymCreateSe::,EAX,[EBX+STM.Program]
         MOV EDI,EAX
    .30: ; Group EDI is being defined/updated. Each ordinal specifies a segment, whose .GroupPtr will be set to EDI.
         BufferRetrieve [EBX+STM.OrdBuffer]
         LEA EDX,[ESI+ECX]
    .40: CMP ESI,EDX
         JNB .90:
         PUSH EDX,ESI
           MOV EDX,ESI                               ; Prepare EDX as !1S for the case of error.
           LODSD
           MOV ECX,EAX
           LODSD
           MOV ESI,ECX
           MOV ECX,EAX
           StripSpaces ESI,ECX                       ; Check segment name ESI,ECX. Name must be in braces [].
           CMPB [ESI],'['
           JE .50:
    .E7831b:Msg '7831',EDX                           ; Segment name "!1S" must be in braces [].
           JMP .80:
    .50:   CMPB [ESI+ECX-1],']'
           JNE .E7831b:
           INC ESI
           SUB ECX,2
           StripSpaces ESI,ECX
           JECXZ .E7831b:
           ; Find a segment (group member) by name ESI,ECX. If not exists, create it.
           Invoke SssFindByName,sssTypeMask,0,ESI,ECX,0
           JC .60:
           JSt [EAX+SSS.Status],sssSegment, .70:
           Msg '7830',EAX,[EAX+SSS.LinePtr]          ; Object [!1S] defined in !2@ is not a segment.
           JMP .80:
    .60:   ; Pseudoinstruction GROUP declares segment which was not defined yet. Let's create it (with default width and alignment).
           MOV EAX,[EBX+STM.Program]
           MOV EAX,[EAX+PGM.Pgmopt.Status]
           AND EAX,pgmoptWidthMask
           OR EAX,sssSegment+sssSection+sssPublic+sssDefinedInGroup
           Invoke SssCreateSe::,EBX,0,ESI,ECX,EAX,0,16
           MOV ECX,[EBX+STM.LinePtr]
           MOV [EAX+SSS.SegmPtr],EAX
           MOV [EAX+SSS.GroupPtr],EDI
           MOV [EAX+SSS.LinePtr],ECX
    .70:   MOV EDX,[EAX+SSS.GroupPtr]                ; Warn when group membership changes.
           MOV [EAX+SSS.GroupPtr],EDI
           TEST EDX
           JZ .80:
           CMP EDX,EDI
           JE .80:
           Msg '3203',EAX,EDX,[EDX+SSS.LinePtr]      ; Segment [!1S] was member of group [!2S] defined in !3@.
    .80: POP ESI,EDX
         ADD ESI,8
         JMP .40:                                    ; Try the next ordinal operand.
    .90: SetSt [Src.Lst.Status::],lstSectInline+lstNoData
    .99:EndProcedure PseudoGROUP

↑ PseudoSTRUC Stm
  Pseudoinstruction STRUC handler.
Manual
  STRUC
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxCreate EaBufferRelease EaBufferReserve SssCreateStructure SssFindByName StmCheckFields StmGetIiModifiers SymDelocalName
Tested by
  t2500 t2501 t2504

    PseudoSTRUC Procedure Stm
    StrucNameBuf LocalVar
    Ii           LocalVar Size=SIZE#II               ; Temporary structire II used for StmGetIiModifiers.
         ClearLocalVar
         MOV EBX,[%Stm]
         JNSt [EBX+STM.CtxStatusAll],ctxNoEmit,.20:
         StackPush [Src.CtxStack::],0                ; In noemitting state only create ctxSTRUC.
         Invoke CtxCreate::,EAX,ctxSTRUC+ctxNamespace+ctxNoEmit,EBX
         JMP .90:
     .20:Invoke StmCheckFields::,EBX,"1001"
         JC .90:
         Invoke EaBufferReserve::,PseudoSTRUC
         MOV [%StrucNameBuf],EAX
         Invoke SymDelocalName::,[EBX+STM.LabelPtr],[EBX+STM.LabelSize],EAX,memberDelocal
         JC .80:
         BufferRetrieve EAX
         ; ESI,ECX is now delocalized structure name. Check for duplicate STRUC declaration.
         Invoke SssFindByName::,sssStructure,0,ESI,ECX,0
         JC .50:                                     ; Jump when OK, not found yet.
         SUB ECX,ECX                                 ; An existing structure EAX is redeclared, erase .Org and old members.
         MOV [EAX+SSS.OrgLow],ECX
         MOV [EAX+SSS.TopLow],ECX
         BufferClear [EAX+SSS.EmitBuffer]
         BufferClear [EAX+SSS.SssOrdBuffer]
         JNSt [EAX+SSS.Status],sssDefinedInPass,.60: ; Found but it was created in previous pass. This is OK.
         Msg '7834',EAX,[EAX+SSS.LinePtr]            ; Structure "!1S" was already declared in !2@.
         JMP .80:
     .50:LEA EDI,[%Ii]
         Invoke StmGetIiModifiers::,EBX,EDI
         MOV EDX,[EDI+II.Align]                      ; EDX is explicit alignment, or 0.
         MOV EAX,[EBX+STM.Program]                   ; Otherwise use program width as the default structure alignment.
         MOV EAX,[EAX+PGM.Pgmopt+PGMOPT.Status]
         AND EAX,pgmoptWidthMask ; Also synchronized with sssWidthMask.
         TEST EDX
         JNZ .58:                                    ; Skip when ALIGN= was explicitly specified.
         MOV DL,2                                    ; Otherwise set structure alignment depending on program width.
         JSt EAX,sssWidth16,.58:
         MOV DL,8
         JSt EAX,sssWidth64,.58:
         MOV DL,4
     .58:OR EAX,sssStructure+sssDefinedInPass
         Invoke SssCreateStructure::,EBX,ESI,ECX,EAX,EDX
         JC .80:
     .60:MOV EDI,EAX                                 ; ^SSS.
         StackPush [Src.CtxStack::],0
         Invoke CtxCreate::,EAX,ctxSTRUC+ctxDefinition+ctxNamespace, EBX
         MOV [EAX+CTX.ObjPtr],EDI
         SetSt [Src.Lst.Status::],lstSectInline      ; Display [Segm] in dump column on the same line.
         MOV EDX,[EBX+STM.Program]
         MOV [EBX+STM.Section],EDI                   ; Change current section to the new structure.
         MOV ECX,[EDX+PGM.CurrentSect]               ; Section to return to after ENDSTRUC (in case of structure definition).
         MOV [EAX+CTX.PreviousSect],ECX
     .80:Invoke EaBufferRelease::,[%StrucNameBuf]
     .90:EndProcedure PseudoSTRUC

↑ PseudoENDSTRUC Stm
  Pseudoinstruction ENDSTRUC handler.
Manual
  STRUC
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  CtxDiscard CtxFind StmCheckFields
Tested by
  t2500 t2501 t2504

    PseudoENDSTRUC Procedure Stm
         MOV EBX,[%Stm]
         Invoke CtxFind::,ctxSTRUC,EBX
         Msg cc=C,'7120',Dict_PseudoENDSTRUC::       ; Wrong nesting, unexpected !1S.
         JC .90:
         Msg cc=NE,'7110',Dict_PseudoENDSTRUC::,EAX  ; Wrong nesting, expected "!1S !2S".
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.60:
         MOV ECX,[EAX+CTX.PreviousSect]              ; Section before entering STRUC/ENDSTRUC block.
         MOV [EBX+STM.Section],ECX                   ; Tell StmFlush to change the section in Pgm.
     .60:SetSt [Src.Lst.Status::],lstSectKeep        ; Do not display the change in this listing line yet.
         MOV ESI,[EAX+CTX.ObjPtr]                    ; ^SSS - ending structure.
         Invoke CtxDiscard::,EAX,EBX
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90:
         Invoke StmCheckFields::,EBX,"00?0"
         ; If it's the final pass and statement is not in included source, warn when the structure was never used.
         TEST ESI
         JZ .90:
         JSt [ESI+SSS.Status],sssUsed,.90:
         JSt [EBX+STM.Status],stmIncluded,.90:
         MOV EDX,[EBX+STM.Program]
         JNSt [EDX+PGM.Status],pgmLastPass,.90:
         Msg PgmStatus=pgmLastPass,'2102',ESI        ; Structure !1S was defined but never used.
     .90:EndProcedure PseudoENDSTRUC

↑ PseudoEQU Stm
  Pseudoinstruction EQU alias `=` handler.
Manual
  EQU
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  ExpConvertToNumber ExpEval ExpWidth LstSet StmCheckFields StmCheckLabel$ SymCreate
Tested by
  t2551 t2553

    PseudoEQU Procedure Stm
    EquExp LocalVar Size=SIZE#EXP                    ; EXP of the operand.
    EquVal LocalVar Size=8                           ; Hexadecimal value of symbol, big endian.
         MOV EBX,[%Stm]
         SetSt [Src.Lst.Status::],lstEQU
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90:
         Invoke StmCheckFields::,EBX,"1010"          ; Label and 1 operand is mandatory.
         JC .90:
         BufferRetrieve [EBX+STM.OrdBuffer]
         MOV ECX,[ESI+4]
         MOV ESI,[ESI+0]
         LEA EDI,[%EquExp]
         Invoke ExpEval::,EDI,ESI,ECX,EBX            ; Evaluate the ordinal operand to expression in EDI.
         SUB ECX,ECX                                 ; Test the special case when assigned symbol is $.
         Invoke StmCheckLabel$::,EBX
         JNE .20:                                    ; Skip when the label is not $.
         INC ECX                                     ; ECX=1 if assigned symbol is $. ECX=0 otherwise.
    .20: MOV EAX,[EDI+EXP.Status]
         Dispatch AL,'N','A','G',0x23
    .E6631:Msg '6631'                                ; Number or address expected.
    .0x23:MOV EAX,[EBX+STM.OffsetLow]                ; Invalid value will be treated as $ (address of the current origin).
         MOV EDX,[EBX+STM.OffsetHigh]
         MOV ESI,[EBX+STM.Section]
         JMP .30:
    .G:  Invoke ExpConvertToNumber::,EDI             ; Symbol EQU CharConst.
         JC .E6631:
    .N:                                              ; Symbol EQU scalar.
    .A:  MOV EAX,[EDI+EXP.Low]                       ; Symbol EQU address.
         MOV EDX,[EDI+EXP.High]
         MOV ESI,[EDI+EXP.Seg]
     .30:JECXZ .60:                                  ; Skip when the assigned symbol is not $.
         TEST ESI
         JNZ .35:
         MOV ESI,[EBX+STM.Section]                   ; If $ EQU scalar, it is assumed to be an offset from the current section.
    .35: CMP ESI,[EBX+STM.Section]                   ; $ EQU Address must be in the current section.
         JE .40:
         Msg '6634'                                  ; Origin offset "$" may be equated only within the current section or structure.
         JMP .0x23:
     .40:MOV ESI,[EBX+STM.Section]
         SUB EAX,[ESI+SSS.OrgLow]
         SBB EDX,[ESI+SSS.OrgHigh]
         TEST EDX                                    ; EDX may be 0 or -1 only.
         JZ .50:
         INC EDX
         JZ .50:
         Msg '6635'                                  ; Origin offset "$" cannot be equated more than 4 GB away.
     .50:MOV [EBX+STM.AlignBytes],EAX
         JMP .90:
     .60:SUB ECX,ECX                                 ; Assigned symbol is not "$". It may be in any section or plain number.
         MOV CL,[EDI+EXP.Status]
         MOV [EBX+STM.Status],CL                     ; Symbol type is copied from the expression type.
         MOV [EBX+STM.OffsetLow],EAX
         MOV [EBX+STM.OffsetHigh],EDX
        ; Prepare symbol value for listing. Its section will be in Lst.Section, its value goes to Lst.SetBuffer.
        ; Displayed width (16,32,64) corresponds with current section width but it may be increased if necessary.
         MOV [Src.Lst.Section::],ESI
         MOV EDI,[EBX+STM.Program]
         MOV ESI,sssWidth16                          ; Default section width if Pgm is not set.
         TEST EDI
         JZ .70:
         MOV EDI,[EDI+PGM.CurrentSect]
         TEST EDI
         JZ .70:
         MOV ESI,[EDI+SSS.Status]
     .70:LEA EDI,[%EquVal]
         Invoke ExpWidth::                           ; CL=magnitude of the number in EDX:EAX.
         Dispatch CL,expWidth8B,expWidth4B
    .expWidth2B:
         JSt ESI,sssWidth32|sssWidth64,.expWidth4B:  ; Listing of EQU symbol is DWORD in 32bit mode.
         XCHG AH,AL
         MOV [EDI],AX                                ; Listing of EQU symbol is WORD in 16bit mode.
         MOV CL,2
         JMPS .80:
    .expWidth4B:
         JSt ESI,sssWidth64,.expWidth8B:             ; Listing of EQU symbol is QWORD in 64bit mode.
         BSWAP EAX
         MOV [EDI],EAX
         MOV CL,4
         JMPS .80:
    .expWidth8B:
         BSWAP EDX
         MOV [EDI],EDX
         BSWAP EAX
         MOV [EDI+4],EAX
         MOV CL,8
     .80:; Symbol section is temporarily stored to Stm.Section but it will be restored from ESI after SymCreate,
         ;    because EQU never changes the current section.
         MOV ESI,[Src.Lst.Section::]
         XCHG [EBX+STM.Section],ESI
         Invoke LstSet::,EDI,ECX                     ; EQUated symbol will be listed by its value.
         MOV EAX,stmLabelIsPublic
         AND EAX,[EBX+STM.Status]
         OR  EAX,symDefined
         Invoke SymCreate::,EAX,[EBX+STM.LabelPtr],[EBX+STM.LabelSize],EBX
         MOV [EBX+STM.Section],ESI                   ; Leave the current section as it was before PseudoEQU.
     .90:EndProcedure PseudoEQU

↑ PseudoINCLUDE Stm
  Pseudoinstruction INCLUDE handler.
Manual
  INCLUDE
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  ChunkInclude
Tested by
  t1220 t2401 t2402 t2403

    PseudoINCLUDE Procedure Stm
         MOV EBX,[%Stm]
         Invoke ChunkInclude::,EBX
        EndProcedure PseudoINCLUDE

↑ PseudoINCLUDE1 Stm
  Pseudoinstruction INCLUDE1 handler.
Manual
  INCLUDE1
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invokes
  ChunkInclude

    PseudoINCLUDE1 Procedure Stm
         MOV EBX,[%Stm]
         SetSt [EBX+STM.Status],stm1
         Invoke ChunkInclude::,EBX
        EndProcedure PseudoINCLUDE1

↑ PseudoINCLUDEHEAD Stm
  Pseudoinstruction INCLUDEHEAD handler.
Manual
  INCLUDEHEAD
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  ChunkInclude
Tested by
  t1230 t1233 t2420

    PseudoINCLUDEHEAD Procedure Stm
         MOV EBX,[%Stm]
         SetSt [EBX+STM.Status],stmIncludeHead
         Invoke ChunkInclude::,EBX
        EndProcedure PseudoINCLUDEHEAD

↑ PseudoINCLUDEHEAD1 Stm
  Pseudoinstruction INCLUDEHEAD1 handler.
Manual
  INCLUDEHEAD1
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invokes
  ChunkInclude

    PseudoINCLUDEHEAD1 Procedure Stm
         MOV EBX,[%Stm]
         SetSt [EBX+STM.Status],stm1+stmIncludeHead
         Invoke ChunkInclude::,EBX
        EndProcedure PseudoINCLUDEHEAD1

↑ PseudoINCLUDEBIN Stm
  Pseudoinstruction INCLUDEBIN handler.
Manual
  INCLUDEBIN
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  ChunkInclude

    PseudoINCLUDEBIN Procedure Stm
         MOV EBX,[%Stm]
         SetSt [EBX+STM.Status],stmIncludeBin
         Invoke ChunkInclude::,EBX
       EndProcedure PseudoINCLUDEBIN

↑ PseudopcERROR Stm
  Pseudoinstruction %ERROR handler.
Manual
  %ERROR
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  EaBufferRelease EaBufferReserve ExpEvalNum StmCheckFields

    PseudopcERROR Procedure Stm
    MsgId   LocalVar ; '5000' decadic ID.
    MsgText LocalVar Size=8
         MOV EBX,[%Stm]
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90:
         Invoke StmCheckFields::,EBX,"00*?"
         JC .90:
         SetSt [Src.Lst.Status::],lstNoData
      ;  Get message Id.
         SUB EDX,EDX
         BufferRetrieve [EBX+STM.KeyBuffer]
         TEST ECX
         JZ .20: ; No ID= specified, use default 5000.
         ; Only one keyword accepted: ID=.
         CMPD [ESI+4],2 ; Keyname size.
         JNE .W3870:
         MOV EAX,[ESI+0] ; Keyword name pointer.
         MOV AX,[EAX] ; Two characters of keyword.
         AND AX,0xDFDF ; Convert them to uppercase.
         CMP AX,'ID'
         JE .10:
    .W3870: Msg '3870',ESI ; Ignored illegal %%ERROR option "!1S". Expected ID=.
         JMPS .40:
     .10:Invoke ExpEvalNum::,[ESI+8],[ESI+12]
         JC .20:
         TEST EDX
         JNZ .W3872:
         CMP EAX,5999
         JA .W3872:
         CMP EAX,5000
         JAE .30:
         ADD EAX,5000
         CMP EAX,5999
         JA .W3872:
         CMP EAX,5000
         JAE .30:
    .W3872:Msg '3872',EAX ; Wrong %%ERROR ID=!1D, expected 0..999 or 5000..5999.
    .20: MOV EAX,5000 ; Default ID when wrong or none provided.
    .30: ADD ESI,16 ; Next keyword, if any.
         CMP ECX,16
         JA .W3870:
    .40: LEA EDI,[%MsgId]
         StoD EDI,Size=4
         BufferRetrieve [EBX+STM.OrdBuffer]
         JCXZ .70:
         Invoke EaBufferReserve::,PseudopcERROR
         MOV EDX,EAX
    .50: BufferStore EDX,[ESI+0],[ESI+4] ; Concatenate %ERROR comma-separated ordinals to one line of text.
         BufferStoreByte EDX,','
         ADD ESI,8
         SUB ECX,8
         JA .50:
         BufferDecrement EDX ; Remove the last comma.
         BufferRetrieve EDX
         Invoke EaBufferRelease::,EDX
    .70: LEA EDI,[%MsgText]
         MOV [EDI+0],ESI
         MOV [EDI+4],ECX
         Msg [%MsgId],EDI
    .90:EndProcedure PseudopcERROR

↑ PseudoLINK Stm
  Pseudoinstruction LINK handler. Specified filenames or filemasks will be made persistent and stored to Pgm.LinkFileNamesTable, in the final pass only. The actual linking is performed later in PgmDestroy.
Manual
  LINK
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  StmCheckFields

    PseudoLINK Procedure Stm
         MOV EBX,[%Stm]
         StmInStruc EBX,.90:                    ; Do not allow this statement in a structure definition.
         SetSt [Src.Lst.Status::],lstNoData
         JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90:
         Invoke StmCheckFields::, EBX,"00*0"
         MOV EDX,[EBX+STM.Program]
         TEST EDX
         JZ .90:                                ; This is unexpected behaviour.
         JNSt [EDX+PGM.Status],pgmLastPass,.90: ; Instruction LINK is processed in final pass only.
         BufferRetrieve [EBX+STM.OrdBuffer]
         TEST ECX
         JZ .90:                                ; If no operands.
    .20: LODSD                                  ; Load a pointer to the next operand.
         MOV EDI,EAX
         LODSD                                  ; EDI,EAX is now a string with filename/filemask.
         PUSH ECX,ESI
           MOV ECX,[EDX+PGM.LinkFilesNr]
           MOV ESI,[Ea.Eaopt.MaxLinks::]
           CMP ECX,ESI
           JB .30:                              ; ESI,ECX will be popped at .80:.
           Msg '7703',ESI                       ; Number of linked files exceeded MaxLinks=!1D.
          POP ESI,ECX
          JMP .90:                              ; Abort further linking when MaxLinks exceeded.
     .30: MOV ESI,EDI
          MOV ECX,EAX
          StripSpaces ESI,ECX
          StripQuotes ESI,ECX
          JECXZ .80:
          INC ECX                              ; Room for zero terminator.
          PoolNew [EDX+PGM.Pool],ECX,Align=Byte
          MOV EDI,EAX
          DEC ECX
          REP MOVSB
          MOV ESI,EAX
          SUB EAX,EAX
          STOSB
          MOV ECX,[EDX+PGM.LinkFilesNr]
          MOV EDI,[EDX+PGM.LinkFileNamesTable]
          MOV [EDI+4*ECX],ESI
          MOV EDI,[EDX+PGM.LinkLinePtrTable]
          MOV EAX,[EBX+STM.LinePtr]
          MOV [EDI+4*ECX],EAX
          INC ECX
          MOV [EDX+PGM.LinkFilesNr],ECX
     .80:POP ESI,ECX
         SUB ECX,8
         JA .20:
    .90:EndProcedure PseudoLINK

↑ PseudoScope Statement, Scope
  Common handler for pseudoinstructions GLOBAL,PUBLIC,EXTERN,EXPORT,IMPORT.
Input
  Statement Pointer to the statement parsed in STM structure.
  Scope is one of the flags from symScopeMask.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  DictLookup StmCheckFields SymCreate SymDynamicLink
Invoked by
  PseudoEXPORT PseudoEXTERN PseudoGLOBAL PseudoIMPORT PseudoPUBLIC

    PseudoScope Procedure Statement, Scope
    DllNameSize LocalVar
    DllNamePtr  LocalVar
    FwdNameSize LocalVar
    FwdNamePtr  LocalVar
        ClearLocalVar
        MOV EBX,[%Statement]
        MOV EDX,[%Scope]
        JSt [EBX+STM.CtxStatusAll],ctxNoEmit,.90:
        SetSt [Src.Lst.Status::],lstNoData
        Invoke StmCheckFields::, EBX,"*0**" ; Warn if machine prefix is present in statement.
        JNSt EDX,symImport|symExport,.40:
        ; IMPORT and EXPORT may specify dynamic library LIB=.
        BufferRetrieve [EBX+STM.KeyBuffer]
        JECXZ .40:
    .10:; EXPORT may specify forward symbol FWD= and its dynamic library LIB=.
        Invoke DictLookup::,DictDynLinkKeys::,[ESI+0],[ESI+4] ; Only FWD= and LIB= is expected.
        Dispatch AL,dictKeyLIB,dictKeyFWD
    .W3866:Msg '3866',ESI ; Ignored illegal option "!1S=".
        JMP.30:
    .dictKeyLIB:
        JNSt EDX,symImport|symExport,.W3866:
        MOV EDI,[ESI+8]  ; New LIB= valuePtr.
        MOV EAX,[ESI+12] ; New LIB= valueSize.
        StripQuotes EDI,EAX ; Quotes are optional.
        MOV [%DllNamePtr],EDI
        MOV [%DllNameSize],EAX
        JMP .30:
    .dictKeyFWD:
        JNSt EDX,symExport,.W3866:
        MOV EDI,[ESI+8]  ; New FWD= valuePtr.
        MOV EAX,[ESI+12] ; New FWD= valueSize.
        MOV [%FwdNamePtr],EDI
        MOV [%FwdNameSize],EAX
    .30:ADD ESI,16 ; Inspect other keywords, if any, to detect unexpected keys.
        SUB ECX,16
        JG .10: ; The next keyword operand.
    .40:JNSt [EBX+STM.Status],stmLabelPresent, .55:
        ; Declare symbol with scope EDX from the label field.
    .50:Invoke SymCreate::,EDX,[EBX+STM.LabelPtr],[EBX+STM.LabelSize],EBX
        Invoke SymDynamicLink::,EAX,[EBX+STM.Program],[%DllNamePtr],[%DllNameSize], \
                                [%FwdNamePtr],[%FwdNameSize]
    .55:BufferRetrieve [EBX+STM.OrdBuffer]
         JECXZ .90:
    .60:; Declare symbol with scope EDX from the ordinal ESI field.
         Invoke SymCreate::,EDX,[ESI+0],[ESI+4],EBX
         Invoke SymDynamicLink::,EAX,[EBX+STM.Program],[%DllNamePtr],[%DllNameSize], \
                                     [%FwdNamePtr],[%FwdNameSize]
    .80: ADD ESI,8
         SUB ECX,8
         JA .60: ; The next ordinal operand.
    .90:EndProcedure PseudoScope

↑ PseudoGLOBAL Stm
  Pseudoinstruction GLOBAL handler.
Manual
  GLOBAL
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  PseudoScope
Tested by
  t2381

    PseudoGLOBAL Procedure Stm
         Invoke PseudoScope,[%Stm],symGlobal
        EndProcedure PseudoGLOBAL

↑ PseudoPUBLIC Stm
  Pseudoinstruction PUBLIC handler.
Manual
  PUBLIC
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  PseudoScope
Tested by
  t2381

    PseudoPUBLIC Procedure Stm
         Invoke PseudoScope,[%Stm],symPublic
        EndProcedure PseudoPUBLIC

↑ PseudoEXTERN Stm
  Pseudoinstruction EXTERN handler.
Manual
  EXTERN
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  PseudoScope
Tested by
  t2381

    PseudoEXTERN Procedure Stm
         Invoke PseudoScope, [%Stm],symExtern
       EndProcedure PseudoEXTERN

↑ PseudoEXPORT Stm
  Pseudoinstruction EXPORT handler.
Manual
  EXPORT
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  PseudoScope

    PseudoEXPORT Procedure Stm
         Invoke PseudoScope,[%Stm],symExport ; +stmPublic
        EndProcedure PseudoEXPORT

↑ PseudoIMPORT Stm
  Pseudoinstruction IMPORT handler.
Manual
  IMPORT
Input
  Stm Pointer to the statement parsed in STM structure.
Output
  Statement is modified.
Error
  Errors are reported with macro Msg.
Invoked from
  StmExecute
Invokes
  PseudoScope

    PseudoIMPORT Procedure Stm
         Invoke PseudoScope, [%Stm],symImport
        EndProcedure PseudoIMPORT

     ENDPROGRAM pseudo

▲Back to the top▲