Object MAC represents a macroinstruction.
Mac objects (macro definitions) are kept on PASS.MacList.
MacList is empty in the beginning of each pass.
Macros defined in program pass are merged with parent program's macros when the last pass terminates.
Scope of macros and %variables is the whole source file.
When a macro is invoked (expanded), its arguments are stored to context,
and assembly is redirected to the macro prototype (%MACRO statement of invoked macro).
Assembly returns below the macro invokation when the coresponding %ENDMACRO
has been assembled.
mac PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32 INCLUDEHEAD "euroasm.htm" ; Interface (structures, symbols and macros) of other modules.
mac HEAD ; Start of module interface.
MAC STRUC .NamePtr D D ; Pointer to macro name. .NameSize D D ; Size of macro name. .LinePtr D D ; Pointer to the first physical line of %MACRO statement (definition of the macro) or 0 when the macro was dropped. .Status D D ; Macro properties. ENDSTRUC MAC
macLabeled = 0x00000001 ; Formal label %: occured at least once in some statement of macro definition.
ENDHEAD mac ; End of module interface.
MacListMerge Procedure ParentPass, ChildPass MOV EBX,[%ParentPass] MOV EDX,[%ChildPass] ListGetFirst [EDX+PASS.MacList] JZ .90: .10 MOV ESI,EAX ; Ptr to MAC. PoolStore [EBX+PASS.Pool],[ESI+MAC.NamePtr],[ESI+MAC.NameSize] MOV [ESI+MAC.NamePtr],EAX ; Reallocated ptr to name. ListStore [EBX+PASS.MacList],ESI ListGetNext ESI JNZ .10: .90:EndProcedure MacListMerge
MacFind Procedure NamePtr, NameSize SUB EDI,EDI MOV [%ReturnEAX],EDI .10: Invoke CtxPeek::,ctxPROGRAM,EDI JC .90: MOV EDI,EAX MOV EBX,[EAX+CTX.ObjPtr] TEST EBX JZ .10: MOV ECX,[EBX+PGM.PassPtr] JECXZ .10: MOV EDX,[ECX+PASS.MacList] ListGetLast EDX .50: JZ .10: Compare [%NamePtr],[%NameSize],[EAX+MAC.NamePtr],[EAX+MAC.NameSize] JE .70: ListGetPrev EAX JMP .50: .70: MOV ECX,[EAX+MAC.LinePtr] STC JECXZ .90: ; Zero LinePtr signalizes that the macro was dropped. CLC MOV [%ReturnEAX],EAX .90:EndProcedure MacFind
Stm.OperationPtr/Size
.
Stm.OperationData
contains pointer to MAC object
and MAC.LinePtr points to the corresponding %MACRO statement with macro definition.
MacExpand Procedure Stm MOV EBX,[%Stm] Invoke StmCheckFields::,EBX,"*0**" StackPush [Src.CtxStack::],0 LEA ECX,[EBX+STM.OperationPtr] Msg cc=C,'9312',ECX ; Allocation error expanding macro !1S. MOV ECX,ctxMACRO+ctxExpansion+ctxExpandable+ctxFormal+ctxPrototype ; Examine listing status. LEA EDX,[Ea.Eaopt::] JNSt [EDX+EAOPT.Status],eaoptLIST,.50: JNSt [EDX+EAOPT.Status],eaoptLISTMACRO,.50: SetSt ECX,ctxMacExpList ; Indicate that macroexpansion should be +listed even ; when the macro is defined in included file and LISTINCLUDE=OFF. .50:Invoke CtxCreate::,EAX,ECX,EBX Invoke MacCtxUpdate,EAX,EBX ; Copy macro operands to context buffers. MOV ECX,[EBX+STM.OperationData] ; Pointer to MAC object with macro declaration. MOV EAX,[ECX+MAC.LinePtr] MOV [EBX+STM.LineNext],EAX ; Continue assembly with macro prototype statement. MOVD [EBX+STM.ChunkNext],0 .90:EndProcedure MacExpand
MacCtxUpdate Procedure CtxPtr, StmPtr McuPassPool LocalVar ; Current program pass pool. MOV EBX,[%StmPtr] MOV EDX,[%CtxPtr] MOV EAX,[EBX+STM.Program] MOV ECX,[EAX+PGM.PassPtr] TEST ECX JNZ .05: .F9312:LEA ECX,[EBX+STM.OperationPtr] Msg '9312',ECX ; Allocation error expanding macro !1S. STC JMP .90: .05: MOV EAX,[ECX+PASS.Pool] TEST EAX MsgUnexpected cc=Z MOV [%McuPassPool],EAX MOV EAX,[EBX+STM.LineEnd] ; LinePtr to the statement which follows macro invokation. MOV EDI,[EBX+STM.ChunkPtr] SUB ECX,ECX MOV [EDX+CTX.LineNext],EAX ; Where to continue when the expansion is over. MOV [EDX+CTX.ChunkNext],EDI MOV [EDX+CTX.Shift],ECX ; Update context with MacPtr from statement and ; copy flag MAC.Status:macLabeled to CTX.Status:ctxMacLabeled to indicate whether %: should be expanded implicitly. MOV ESI,[EBX+STM.OperationData] ; In case of macroinstruction it is ^MAC. MOV [EDX+CTX.MacPtr],ESI JNSt [ESI+MAC.Status],macLabeled,.10: SetSt [EDX+CTX.Status],ctxMacLabeled .10: BufferRetrieve [EBX+STM.OrdBuffer] ; Copy ordinal operands from invokation to context.OrdBuffer. ; ESI,ECX is QWORDs (Ptr,Size) for each ordinal used in macro invokation. ECX is 0,8,16,24,... ; However their lifetime is limited to StmFlush. BufferStore [EDX+CTX.OrdBuffer],ESI,ECX JC .F9312: BufferRetrieve [EDX+CTX.OrdBuffer] ; Ordinal lifetime will be prolonged to the end of macroexpansion. JECXZ .30: ; All ordinals copied. .20: PoolStore [%McuPassPool],[ESI+0],[ESI+4] ; Make the ordinal value persistent till end of pass. JC .F9312: MOV [ESI+0],EAX ADD ESI,8 SUB ECX,8 JA .20: ; Next ordinal. .30: BufferRetrieve [EBX+STM.KeyBuffer] ; Copy keyword operands from invokation to context.KeyBuffer. BufferStore [EDX+CTX.KeyBuffer],ESI,ECX JC .F9312: BufferRetrieve [EDX+CTX.KeyBuffer] ; ESI,ECX is four DWORDs (NamePtr,NameSize,ValPtr,ValSize) for each keyword used in macro invokation. ; Keywords will be made persistent to the end of expansion. JECXZ .50: ; All keywords copied. ECX was 0,16,32,... .40: PoolStore [%McuPassPool],[ESI+0],[ESI+4] ; Make the keyword name persistent. JC .F9312: MOV [ESI+0],EAX PoolStore [%McuPassPool],[ESI+8],[ESI+12] ; Make the keyword value persistent. JC .F9312: MOV [ESI+8],EAX ADD ESI,16 SUB ECX,16 JG .40: ; Next keyword. .50: BufferNew [EDX+CTX.ObjBuffer],6*4 ; Reserve room for 6 Dwords in CTX.ObjBuffer. JC .F9312: MOV EDI,EAX MOV ESI,[EBX+STM.LabelPtr] MOV ECX,[EBX+STM.LabelSize] PoolStore [%McuPassPool],ESI,ECX JC .F9312: ; Copy misc info from invokation to context.ObjBuffer in the format CTX_MAC. MOV [EDI+0],EAX ; 1.Dword: LabelPtr. MOV [EDI+4],ECX ; 2.Dword: LabelSize. MOV ESI,[EBX+STM.OperationPtr] MOV ECX,[EBX+STM.OperationSize] PoolStore [%McuPassPool],ESI,ECX ; Make macroname persistent (it may be used to expand %0). JC .F9312: MOV [EDI+8],EAX ; 3.Dword: macro name ptr. MOV [EDI+12],ECX ; 4.Dword: macro name size. MOV EAX,[EBX+STM.OperationData] MOV [EDI+16],EAX ; 5.Dword: LinePtr to %MACRO prototype in source. MOV EAX,[EBX+STM.Status] MOV [EDI+20],EAX ; 6.Dword: STM.Status of macro invokation. .90:EndProcedure MacCtxUpdate
MacPrototype Procedure CtxPtr, StmPtr MpPassPool LocalVar FrmVar LocalVar Size=16 ; VarNamePtr,VarNameSize,VarValuePtr,VarValueSize FrmMax LocalVar ; Greater of ordinals length in STM.OrdBuffer and CTX.OrdBuffer. 0,8,16,,, FrmNdx LocalVar ; 0,8,16,...FrmMax-8 MOV EBX,[%StmPtr] ; Statement with %MACRO (prototype). MOV EDX,[%CtxPtr] ; Context with invokation operands. MOV EAX,[EBX+STM.Program] MOV ECX,[EAX+PGM.PassPtr] TEST ECX JZ .F9312: MOV EAX,[ECX+PASS.Pool] TEST EAX JZ .F9312: MOV [%MpPassPool],EAX ; Merge ordinal operands. BufferRetrieve [EBX+STM.OrdBuffer] MOV [%FrmMax],ECX BufferRetrieve [EDX+CTX.OrdBuffer] CMP ECX,[%FrmMax] JBE .10: MOV [%FrmMax],ECX .10:SUB ECX,ECX MOV [%FrmNdx],ECX ; Start with the 1st ordinal. .20:LEA EDI,[%FrmVar] ; Loop .20: .. .50: ordinal operands. SUB EAX,EAX MOV ECX,4 REP STOSD ; Clear FrmVar. MOV EDI,[%FrmNdx] CMP EDI,[%FrmMax] JNB .50: BufferRetrieve [EBX+STM.OrdBuffer] CMP EDI,ECX JNB .30: ; Make ordinal name persistent to the end of macro expansion. MOV ECX,[EDI+ESI+4] MOV ESI,[EDI+ESI+0] PoolStore [%MpPassPool],ESI,ECX JC .F9312: MOV [%FrmVar+0],EAX ; Persistent ordinal name ptr. MOV [%FrmVar+4],ECX ; Ordinal name size (may be 0 when the ordinal is unnamed). .30:BufferRetrieve [EDX+CTX.OrdBuffer] CMP EDI,ECX JNB .40: MOV ECX,[EDI+ESI+4] ; Ordinal value size. MOV ESI,[EDI+ESI+0] ; ValuePtr. It's already been made persistent in MacCtxUpdate. MOV [%FrmVar+8],ESI MOV [%FrmVar+12],ECX .40:LEA ESI,[%FrmVar] BufferStore [EDX+CTX.FrmBuffer],ESI,16 JC .F9312: ADDD [%FrmNdx],8 JMP .20: .50:; Merge keyword operands. First store keywords from prototype with their default values. BufferRetrieve [EBX+STM.KeyBuffer] JECXZ .60: .52:PUSH ECX ; Loop .52: .. .60: keyword operands. MOV EDI,[ESI+0] ; NamePtr. MOV ECX,[ESI+4] ; NameSize. ; BufferStore [EDX+CTX.ValBuffer],EDI,ECX PoolStore [%MpPassPool],EDI,ECX JC .F9312: MOV [%FrmVar+0],EAX ; Persistent ordinal name ptr. MOV [%FrmVar+4],ECX ; Ordinal name size. MOV EDI,[ESI+8] ; ValuePtr. MOV ECX,[ESI+12] ; ValueSize. ; BufferStore [EDX+CTX.ValBuffer],EDI,ECX PoolStore [%MpPassPool],EDI,ECX MOV [%FrmVar+8],EAX ; Persistent default value ptr. MOV [%FrmVar+12],ECX ; Persistent default value size. LEA EDI,[%FrmVar] BufferStore [EDX+CTX.FrmBuffer],EDI,16 ; Save keyword with default value. POP ECX JNC .55: .F9312:Msg '9312',EBX ; Allocation error expanding macro !1S. STC JMP .90: .55:ADD ESI,16 SUB ECX,16 ; JA .52: JG .52: .60: ; Each keyword in macro invokation should be found in CTX.FrmBuffer, otherwise W2610, ; and its value will update stored key. BufferRetrieve [EDX+CTX.KeyBuffer] JECXZ .90: .62:PUSH ECX,ESI MOV EDI,[ESI+0] ; Name ptr. MOV EAX,[ESI+4] ; Name size. ; Search for keyword EDI,EAX in CTX.FrmBuffer. BufferRetrieve [EDX+CTX.FrmBuffer] JECXZ .W2610: ; If keyword not found. .70: Compare [ESI+0],[ESI+4],EDI,EAX JE .75: ; If keyword found. ADD ESI,16 SUB ECX,16 ; JA .70: JG .70: .W2610:MOV EAX,[ESP] ; ^QWORD keyword from CTX.KeyBuffer. Msg '2610',EAX,[EBX+STM.LinePtr]; Parameter "!1S=" was not specified in macro prototype at !2@. Ignored. JMPS .80: .75: ; Matching keyword in CTX.FrmBuffer is addressed with ESI, ; its default value will be overwritten with value from CTX.KeyBuffer. MOV EDI,[ESP] ; ^QWORD keyword from CTX.KeyBuffer. MOV EAX,[EDI+8] ; Persistent new key value ptr. MOV ECX,[EDI+12] ; New key value size. MOV [ESI+8],EAX MOV [ESI+12],ECX .80:POP ESI,ECX ADD ESI,16 SUB ECX,16 ;JA .62: JG .62: .90:EndProcedure MacPrototype
ENDPROGRAM mac