@eddy
Here's our version of the above technique. We use it to dynamically create macros that can be used to generate unique procedure and data names in classes and modules. This is just a small sample to show how we create modular code without actually using modules.
We create a standard "_Block_" macro that can be used whenever a unique name needs to be created. The "_Blank_" and "_Colon_" parameters are needed to ensure that PB doesn't misinterpret the macro contents before it's fully generated.
Code: Select all
Macro _Colon_
:
EndMacro
Macro CreateBlockName(_BlockName_, _Blank_=)
_Blank_#Macro _B#_Blank_#lock_#_Colon_#_BlockName_#_Colon_#EndMacro
EndMacro
Macro DestroyBlockName(_Blank_=)
UndefineMacro _B#_Blank_#lock_
EndMacro
Macro BeginClass (bvsClassName)
CreateBlockName(bvsClassName)
EndMacro
Macro EndClass
DestroyBlockName()
EndMacro
Macro typObject
I
EndMacro
Macro DeclareExternalFunction (bvsProcName, bvsDataParmType)
Declare.bvsDataParmType cls#_Block_#_fun#bvsProcName
EndMacro
Macro BeginClassInterface
DeclareExternalFunction(Create, typObject) ()
Interface obj#_Block_
EndMacro
Macro EndClassInterface
EndInterface
EndMacro
BeginClass (ButtonBar) ; Macro _Block_:ButtonBar:EndMacro
BeginClassInterface ; Declare.I clsButtonBar_funCreate ()
; Interface objButtonBar
EndClassInterface ; EndInterface
EndClass ; UndefineMacro _Block_
BeginClass (Button) ; Macro _Block_:Button:EndMacro
BeginClassInterface ; Declare.I clsButton_funCreate ()
; Interface objButton
EndClassInterface ; EndInterface
EndClass ; UndefineMacro _Block_
And for those of you who really love to read my code, here are the two procedures referenced above. As you can see, much of the code is identical, even though the procedures are from two different classes. The underlying code uses the "_Block_" macro to create names that are unique to each class, thereby allowing the entire program to be compiled as a single source file.
Code: Select all
ExternalFunction(Create, typObject) () ; Procedure.I clsButtonBar_funCreate ()
;
; Create - create a class instance
;
Local(Me, strButtonBar) ; Protected *Self.strButtonBar
Me = AllocateMemory(SizeOf(strButtonBar)) ; *Self = AllocateMemory(SizeOf(strButtonBar))
If IsObject(Me) ; If *Self <> 0
InitializeStructure(Me, strButtonBar) ; InitializeStructure(*Self, strButtonBar)
Me\prpVirtualTable = LabelPtr(VirtualTable) ; *Self\prpVirtualTable = ?clsButtonBar_lblVirtualTable
ClassCall(Constructor) (Me) ; clsButtonBar_subConstructor (*Self)
EndIf ; EndIf
ProcedureReturn Me ; ProcedureReturn *Self
EndFunction ; EndProcedure
Code: Select all
ExternalFunction(Create, typObject) () ; Procedure.I clsButton_funCreate ()
;
; Create - create a class instance
;
Local(Me, strButton) ; Protected *Self.strButton
Me = AllocateMemory(SizeOf(strButton)) ; *Self = AllocateMemory(SizeOf(strButton))
If IsObject(Me) ; If *Self <> 0
InitializeStructure(Me, strButton) ; InitializeStructure(*Self, strButton)
Me\prpVirtualTable = LabelPtr(VirtualTable) ; *Self\prpVirtualTable = ?clsButton_lblVirtualTable
ClassCall(Constructor) (Me) ; clsButton_subConstructor (*Self)
EndIf ; EndIf
ProcedureReturn Me ; ProcedureReturn *Self
EndFunction ; EndProcedure
Here are the macros used in the above methods. In total, we use about 500 macros in generating our code. As you can see, I'm a big fan of long names and Polish notation.
Code: Select all
Macro Me
*Self
EndMacro
Macro ExternalFunction (bvsProcName, bvsDataParmType)
Procedure.bvsDataParmType cls#_Block_#_fun#bvsProcName
EndMacro
Macro EndFunction
EndProcedure
EndMacro
Macro ClassCall (bvsProcName)
cls#_Block_#_sub#bvsProcName
EndMacro
Macro Local (bvsDataParmName, bvsDataParmType)
Protected bvsDataParmName.bvsDataParmType
EndMacro
Macro IsObject (bvsDataParmName)
bvsDataParmName <> 0
EndMacro
Macro LabelPtr (bvsDataParmName)
?cls#_Block_#_lbl#bvsDataParmName
EndMacro
For ten years Caesar ruled with an iron hand, then with a wooden foot, and finally with a piece of string.
~ Spike Milligan