Object MAC represents one 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 begins with their definition and ends at the end of source.
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 invocation 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. INCLUDEHEAD \ ; Include headers of another modules used in this module. ctx.htm, \ ea.htm, \ eaopt.htm, \ exp.htm, \ msg.htm, \ pass.htm, \ pgm.htm, \ pgmopt.htm, \ stm.htm, \ \sss.htm, \ syswin.htm, \ ;;
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.
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. JNSt [Ea.Eaopt.Status::],eaoptLIST,.50: JNSt [Ea.Eaopt.Status::],eaoptLISTMACRO,.50: ; Indicate that macroexpansion should be +listed ; even when the macro is defined in included file and LISTINCLUDE=OFF: SetSt ECX,ctxMacExpList .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 invocation. 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 flagMAC.Status:macLabeled
toCTX.Status:ctxMacLabeled
; in order to 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 invocation to context.OrdBuffer. ; ESI,ECX is QWORDs (Ptr,Size) for each ordinal used in macro invocation. 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 invocation 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 invocation. ; 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],SIZE# CTX_MAC JC .F9312: MOV EDI,EAX ; ^CTX_MAC in CTX.ObjBuffer. MOV ESI,[EBX+STM.LabelPtr] MOV ECX,[EBX+STM.LabelSize] PoolStore [%McuPassPool],ESI,ECX JC .F9312: ; Copy misc info from invocation to context.ObjBuffer in the format CTX_MAC. MOV [EDI+CTX_MAC.LabelPtr],EAX ; Label of macro invokation. MOV [EDI+CTX_MAC.LabelSize],ECX 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+CTX_MAC.MacroNamePtr],EAX MOV [EDI+CTX_MAC.MacroNameSize],ECX MOV EAX,[EBX+STM.OperationData] MOV [EDI+CTX_MAC.ProtoLinePtr],EAX ; LinePtr to %MACRO prototype in source. MOV EAX,[EBX+STM.Status] MOV [EDI+CTX_MAC.InvokStmStatus],EAX ; STM.Status of macro invocation. .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 invocation 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. 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. 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 JG .52: .60: ; Each keyword in macro invocation should be found in CTX.FrmBuffer, otherwise W2610, ; and its value will update the 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 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 JG .62: .90:EndProcedure MacPrototype
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
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
ENDPROGRAM mac