EuroAssembler Index Manual Download Source Macros


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

       EUROASM NOWARN=2101,
pseudo PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32,MAXPASSES=64
INCLUDEHEAD "euroasm.htm" ; Interface (structures, symbols and macros) of other modules.
INCLUDEHEAD  \  ; Include headers of another modules used in this module.
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,     \
syswin.htm,  \
;;
pseudo HEAD
         ; This modul has no interface.
       ENDHEAD pseudo
↑ 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.
     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]
     Msg '1160',EDI,[ESI+FILE.Size],EDX          ; "!1$",size=!2K,src=!3$.
     MOV ESI,Ea.SrcFile::                        ; Main source file.
     LEA EDI,[ESI+FILE.Name]
     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]
     Msg '1180',EAX,[ESI+FILE.Size],EDX          ; "!1$",size=!2K,src=included in !3@.
     INC ECX
     JMP .F3:
.F9: RET
     ENDP PseudopcDISPLAY.FILES::

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]
.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.
    MOV [EBX+0],EDI
    MOV [EBX+4],EDX
    JNSt [EAX+CHUNK.Status],chunkError,.I3:
    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 .I2:
      MOV AL,'E'
.I2:  STOSB
      MOV EAX,EDX
      StoD EDI,Size=4,Align=right,LeadingZeroes=yes
      XOR EAX,EAX
      STOSB
    POP EDI,EAX
    JMP .I5:
.I3:MOV EDI,=B"orig"
    JSt [EAX+CHUNK.Status],chunkOrig|chunkOrigBin,.I5:
    MOV EDI,=B"binary"
    JSt [EAX+CHUNK.Status],chunkBin,.I5:
    MOV EDI,=B"source"
    JNSt [EAX+CHUNK.Status],chunkResolved|chunkSkipped,.I5:
    MOV EDI,=B"resolved"
    JNSt [EAX+CHUNK.Status],chunkSkipped,.I5:
    MOV EDI,=B"skipped"
.I5: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*
      ; Comvert 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]
     JECXZ .90:
     MOV ECX,[ECX+PGM.PassPtr]
     JECXZ .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: ; ESI points to Ptr,Size of ordinal.
     MOV EDI,[ESI]
     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
     ; za EAX by nemelo byt nic
     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 (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
     Invoke PgmLinkSections::,EDI
     Invoke PgmDestroy::, EDI,EBX                 ; Combine and link modules and store the output file.
.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 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: ; Unexpected behaviour.
     JNSt [EDX+PGM.Status],pgmLastPass,.90: ; Instruction LINK is processed in final pass only.
     BufferRetrieve [EBX+STM.OrdBuffer]
     JECXZ .90:                             ; If no operands.
.20: LODSD
     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:
       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▲