Page 1 of 2

Test if macro is used - conditional jump...

Posted: Sat Nov 02, 2019 3:15 am
by Dudemeister
I have a question regarding conditional execution (or jump) from one macro to another. I don't know if I use the correct terminology below, so please be patient with me.

Macro One
    !jmp two_label
EndMacro

Macro Two
    If three_label is used in MyProcedure ;pseudo-code to demonstrate what I need...
        !jmp three_label
    Else
        !jmp four_label
    EndIf
EndMacro

Macro Three
    !jmp four_label
EndMacro

Macro Four
    Do something other than jump
EndMacro


Procedure MyProcedure()
    One
        Do something cool here

    Two
        Do something even more cool here

    Four
        Do some clean up here

    ;Note: macro label 'Three' was not used above in this procedure, so execution jumped directly to macro label 'Four'

EndProcedure


Now that I laid out all that above, here is my question:

Does anyone know of a way to test within one macro if a separate macro is being used (or is called) within a procedure.

Ie: When macro 'Two' executes, the flow of execution will "jump" to macro 'Three', but it will do so only if 'Three' is called in that procedure. If macro 'Three' is not called in the procedure, the flow of execution jumps directly to macro 'Four', instead.

What I am testing here is if it is possible to perform conditional jump from one macro to another macro, based on whether the second macro is called in the procedure.

Re: Test if macro is used - conditional jump...

Posted: Sat Nov 02, 2019 9:27 am
by infratec
If you need to jump, you should think about your code. :wink:

Really, I think if you have to use such jumps, your code flow is not like it should be.

And no, there is no way to test if a Macro is in use.
You can only test if a Macro is defined.

Maybe you can create labels and test if the label is defined.

Re: Test if macro is used - conditional jump...

Posted: Sat Nov 02, 2019 9:30 am
by Olliv
Houla...

2 remarks...

1) Please use normalized markups

Code: Select all

[code]Debug "code"
[/code]

2) You should use procedures instead of macros... And in your way, you should use selector

Code: Select all

Dim *Address(255) ; address allocating
; ...
Procedure myProcedure() ; a target address
 Debug "kiki"
EndProcedure
; ...
*Address(0) = @myProcedure() ; set the address
; ...
CallFunctionFast(LabelList(LabelIndex) ) ; equ to Jump or Call
Simpler...

Re: Test if macro is used - conditional jump...

Posted: Sat Nov 02, 2019 11:25 am
by BarryG
Macros can't be called; they're just search/replace of your source code at compile time. Not like procedures.

For example, this source code:

Code: Select all

Macro Counter()
  For c=1 To 10
    n+c
  Next
EndMacro

Counter() ; First "call"

Counter() ; Second "call"

Debug n
Just becomes this when compiled/run:

Code: Select all

For c=1 To 10 ; First "call"
  n+c
Next

For c=1 To 10 ; Second "call"
  n+c
Next

Debug n

Re: Test if macro is used - conditional jump...

Posted: Sat Nov 02, 2019 11:31 am
by djes
No. A macro is not called. Think a macro as a "cut and paste" code before compilation. I think that you'd like something that is usually done in assembly. In assembly, you can even dynamically alter your code, so the 'jump' value could be changed. But these practices tend to disappear, as it has been used in numerous viruses and trojans.
In PB you can mix assembly (for example a dynamic jmp) in normal code, somewhat as olliv does. Also note that a lot a coders will see that as bad code, because it is difficult to maintain and understand. Anyway, for short code speed demonstration or low level it is OK.

Edit> BarryG ;)

Re: Test if macro is used - conditional jump...

Posted: Sat Nov 02, 2019 11:33 am
by BarryG
djes wrote:Edit> BarryG ;)
:lol:

Re: Test if macro is used - conditional jump...

Posted: Sat Nov 02, 2019 11:54 am
by mk-soft
When jumping, it is important to note that it can lead to errors in the program if it is not handled correctly. See in the help for 'FakeReturn'

Better to work with break.

You can also create your own keywords with macros and add them in the editor.
For example 'Do, ExitDo, EndDo'.

Code: Select all

;-TOP

EnableExplicit

Macro Do
  Repeat
EndMacro

Macro ExitDo
  Break
EndMacro

Macro EndDo
  Until #True
EndMacro


Define a = 25

Repeat ; Do
  
  If a < 10
    Debug "Is lower 10"
    Break ; ExitDo
  EndIf
  
  a + 10
  If a > 30
    Debug "Is bigger 30"
    Break ; ExitDo
  EndIf
  
  a * 1000
  
Until #True ; EndDo

Debug "a = " + a

Re: Test if macro is used - conditional jump...

Posted: Sat Nov 02, 2019 12:37 pm
by infratec
As real 'working' code:

Code: Select all

Macro One
  one_label:
  Goto  two_label
EndMacro

Macro Two
  two_label:
  CompilerIf Defined(three_label, #PB_Label)
    Goto three_label
  CompilerElse
    Goto four_label
  CompilerEndIf
EndMacro

Macro Three
  three_label:
  Goto  four_label
EndMacro

Macro Four
  four_label:
  Debug "4"
EndMacro


Procedure MyProcedure()
  One
  Debug "Do something cool here"
  
  Two
  Debug "Do something even more cool here"
  
  Four
  Debug "Do some clean up here"
  
  ;Note: macro label 'Three' was not used above in this procedure, so execution jumped directly to macro label 'Four'
  
EndProcedure

MyProcedure()

Re: Test if macro is used - conditional jump...

Posted: Sat Nov 02, 2019 5:05 pm
by Dudemeister
@infratec

Your genius there is exactly what I was looking for, and it's working great. Now, before I unveil my mad experiment that I am doing with this, I need to know one last thing related to this.

Regarding the compiler directive:

Code: Select all

CompilerIf Defined(three_label, #PB_Label)
    Goto three_label
CompilerElse
    Goto four_label
CompilerEndIf
This structure worked perfectly in the majority of my experimental code, but there is one spot where I need the negation of "CompilerIf Defined()". So, my new question that arises from this is, does PB have a negation keyword similar to Not? I can't find one in the documentation (yet) so I thought I'd ask to be sure.

Example:

Code: Select all

CompilerIf Not Defined(three_label, #PB_Label)
    Goto four_label
CompilerEndIf

Or...

CompilerIf Defined(three_label, #PB_Label) = False
    Goto four_label
CompilerEndIf
Are either of the above examples possible in PB? The reason I ask about this is because in one spot, if "three_label" is defined, I don't want anything to happen. But if "three_label" is not defined, then I want it to goto "four_label", and I don't want to be left to write sloppy code like this:

Code: Select all

CompilerIf Defined(three_label, #PB_Label)
    ;leave blank so that nothing happens
CompilerElse
    Goto four_label
CompilerEndIf

Re: Test if macro is used - conditional jump...

Posted: Sat Nov 02, 2019 5:10 pm
by Dudemeister
@Olliv
Olliv wrote:Houla...

2 remarks...

1) Please use normalized markups
I deeply apologize. Despite having programmed for 30+ years (in other languages), this is my first time ever using an online forum. So, please forgive my slowness at learning the proper protocol for doing things.

Re: Test if macro is used - conditional jump...

Posted: Sat Nov 02, 2019 6:08 pm
by Marc56us
This structure worked perfectly in the majority of my experimental code, but there is one spot where I need the negation of "CompilerIf Defined()". So, my new question that arises from this is, does PB have a negation keyword similar to Not? I can't find one in the documentation (yet) so I thought I'd ask to be sure.
The negation operator exists of course in PB (as in all languages): Not (some others languages use '!')
:arrow: Variables and Types

And it is easy to test

Code: Select all

#PureConstant = 10

CompilerIf Defined(PureConstant, #PB_Constant) 
    Debug "Constant IS declared"
CompilerEndIf

; Test 'Not'
CompilerIf Not Defined(Constant_not_declared, #PB_Constant) 
    Debug "Constant is NOT declared"
CompilerEndIf

Code: Select all

Constant IS declared
Constant is NOT declared
"Not" is also very convenient to make code easy to maintain.

Code: Select all

If Not OpenFile(...
While Not Eof(...
So it is enough to search all the " Not " to go to all the locations to be processed next as in an error handler.
I do this systematically, so as not to forget to process the possible error before the rest of the code.

Re: Test if macro is used - conditional jump...

Posted: Sat Nov 02, 2019 7:25 pm
by Dudemeister
@Marc56us

Thank you, Sir!

That was very lacking on my part to not think to look in among the operators...

Update: > I just found I can download a PDF version of the PB manual. It's a bit more searchable than the online version.

Re: Test if macro is used - conditional jump...

Posted: Sat Nov 02, 2019 8:34 pm
by infratec
I never used something else than the inbuild help :wink:

Or ... this forum. :mrgreen:

Re: Test if macro is used - conditional jump...

Posted: Sun Nov 03, 2019 8:53 am
by #NULL
infratec wrote:And no, there is no way to test if a Macro is in use.
You can only test if a Macro is defined.
It's actually the other way round. There is no #PB_Macro for Defined() so you can't know if it's defined, even though you can undefine it. But you can define a constant in a macro to indicate that the macro has been used up to the current point in compiletime. Works only with multiline macro bodies.

Code: Select all


Macro foo
  Debug "foo"
  #_foo_used = 1
EndMacro

Debug "macro used : " + Defined(_foo_used, #PB_Constant)  ; 0
foo
Debug "macro used : " + Defined(_foo_used, #PB_Constant)  ; 1
UndefineMacro foo
Debug "macro used : " + Defined(_foo_used, #PB_Constant)  ; 1


Re: Test if macro is used - conditional jump...

Posted: Sun Nov 03, 2019 11:50 am
by Olliv
@Dudemeister

30 years... Welcome. Test

Code: Select all

PBCompiler.EXE PureBasicFile.PB /Commented
on command prompt to get Assembly equivalent file (named PureBasic.ASM). You could see CallFunctionFast() is equ to CALL [xxx] in ASM language.

As you maybe know Call and Jmp are different : 'Call' uses the stack (pointed with ESP or RSP CPU register) and restores EIP (or RIP on X64 version, old reg was just 'IP' meaning Instruction Pointor) from the stack when single RET ASM statement is found (equ to basic native RETURN statement).

So, with JuMP, you have to manage the end of routine.
Macro can be used, but two difficulties are there :

1) Recursivity is forbidden and often fatally warned on compiling.
2) Macro syntax is very very hard.

i.e.

Code: Select all

; macro version

Macro ICountMyselfOnCompiling()
Debug MacroExpandedCount

; but I can be concatenated on basis user keywords...
#I# MacroExpandedCount = MacroExpandedCount * MacroExpandedCount ; here mul op is pre-calculated (square result is a meta data)

EndMacro

ICountMyselfOnCompiling()
Debug #I1
ICountMyselfOnCompiling()
Debug #I2


; procedure version (Stack is just used to store origin address value, and, optionally, Y value)
Procedure ICountWithHardStack()
Static X ; (Careful : Stack is not used for X integer)
Define Y = 100 ; (But Y is stored in stack, temporarily)
X + Y ; equ to X = X + Y
Debug X
; But concatenate X or Y directly in value names, is unabled... Just enabled on macros...
EndProcedure

ICountWithHardStack()
ICountWithHardStack()
Debug Y ; 0 because Y is erased : Its name is unknown here, and its value is in an obsolete place in stack now...
Be careful to external PDF help file you can find on www. You should check on this forum if it is a right version !