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 used in this source.
ctx.htm,ea.htm,eaopt.htm,exp.htm,msg.htm,pass.htm,pgm.htm,pgmopt.htm,stm.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.
[.text]
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 flag MAC.Status:macLabeled to CTX.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]
TEST ECX
JZ .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