Macros

Just starting out? Need help? Post your questions and find answers here.
User avatar
luis
Addict
Addict
Posts: 3715
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy
Contact:

Macros

Post by luis »

Helpfile wrote: A macro is a placeholder for some code (one keyword, one line or even many lines), which will be directly inserted in the source code at the place where a macro is used

Code: Select all

#PBCONST = 0

Macro BLOCK_START
CompilerIf (#PBCONST= 1)
EndMacro

Macro BLOCK_END
CompilerEndIf
EndMacro


BLOCK_START 
Debug "some code" 
BLOCK_END 

; should expand to
;
; #PBCONST = 0
; 
; CompilerIf (#PBCONST= 1)
; Debug "some code" 
; CompilerEndIf

Is there a way to make this work ?
User avatar
STARGÅTE
Addict
Addict
Posts: 1614
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: Macros

Post by STARGÅTE »

PureBasic is a one-time parser.
In the moment, where the compiler arrives BLOCK_START it evaluates CompilerIf (#PBCONST= 1) to false and no more code is compiled, even not other macros, until an explicit written CompilerEndIf is reached.
Your code is compiled to:

Code: Select all

#PBCONST = 0
CompilerIf (#PBCONST= 1)
BLOCK_END is ignored and should be ignored!

You can Try:

Code: Select all

#PBCONST = 0

Macro CompilerIfBlock
	CompilerIf (#PBCONST= 1)
EndMacro


CompilerIfBlock 
Debug "some code" 
CompilerEndIf
PB 5.73 ― Win 10, 20H2 ― Ryzen 9 3900X ― Radeon RX 5600 XT ITX ― Vivaldi 4.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
User avatar
luis
Addict
Addict
Posts: 3715
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy
Contact:

Re: Macros

Post by luis »

Thank you for the explanation.
If that's what PB is doing it explains what's happening.
But I don't see why it has to be that way.

Based on what you wrote:
wrote:no more code is compiled, even not other macros, until an explicit written CompilerEndIf is reached.
this is my understanding of what's happening, correct me if I'm wrong.


1) The compiler encounters the invokation of BLOCK_START, it expands it to
CompilerIf (#PBCONST= 1)
and evaluates it at compile time deciding it is False.
At this point starts to ignore everything until it encounters a CompilerElse or CompilerEndIf

2) The compiler encounters and ignores
;Debug "some code"

3) The compiler encounters and ignores
;BLOCK_END

4) and goes on ignoring everything else, until it reaches the end of the source and raise the error because it didn't found a CompilerEndIf.


What is macro as PB seems to intend it ?
Helpfile wrote:A macro is a placeholder for some code which will be directly inserted in the source code at the place where a macro is used
So a macro is a fragment of code which has been given a name and whenever the name is invoked it is replaced by the contents of the macro.

Based on the above the compiler should compile the source resulting from the plain code in the source plus any macro expansion.


In my view this is what should happen with the source I posted in the first post:

1) The compiler encounters the constant definition.

2) The compiler encounters two macros definitions.

3) The compiler encounters the invokation of BLOCK_START, it's a macro so it must be expanded, and this results in
CompilerIf (#PBCONST= 1)
then it evaluates it at compile time deciding it is False.

4) The compiler encounters something which is not a macro, it's inside the block of code it shouldn't be compiled and so ignores it
;Debug "some code"

5) The compiler encounters the invokation of BLOCK_END, it's a macro so it must be expanded, and this results in
CompilerEndIf
this is closing the CompilerIf - CompilerEndIf block and all it's fine.

Considering these two different outcomes, is there any good reason why macro expansion shouldn't be treated like in the second example ?

A simple parameter-less macro should simply be a substitute for typing.
Instead of typing some code I write "A" in the source.
If the original code was valid, replacing A with that same code by expanding the macro should still be valid and yield the same results.
User avatar
STARGÅTE
Addict
Addict
Posts: 1614
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: Macros

Post by STARGÅTE »

Your first list is a correct interpretation what is happened.

Your second idea "Based on the above the compiler should compile the source resulting from the plain code in the source plus any macro expansion." is not possible in a single-path compiler like PureBasic.

The PureBasic compiler just goes one times through the lines of the original source code and generates a "new version" of compilation.
5) The compiler encounters the invokation of BLOCK_END, it's a macro so it must be expanded, and this results in
CompilerEndIf
Considering these two different outcomes, is there any good reason why macro expansion shouldn't be treated like in the second example?
Yes, because the BLOCK_END is called inside a false-evaluated CompilerIf block. It would be bad if this code were evaluated, because BLOCK_END could also contain OS-based oder platform-based code like x64-ASM code. Such code would instantly generate a compiler error on x86.

One can argue, that the compiler can expand the macro but ignore all lines from that macro except a CompilerEndIf. But this can generate trouble if more CompilerIf statements are inside the macro itself, right?
PB 5.73 ― Win 10, 20H2 ― Ryzen 9 3900X ― Radeon RX 5600 XT ITX ― Vivaldi 4.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
#NULL
Addict
Addict
Posts: 1364
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Macros

Post by #NULL »

I think the CompilerIf is evaluated while parsing the macro body, so the resulting macro content doesn't contain a CompilerIf anymore. From my understanding macros and compiler-directives kind of work on the same 'level', so their nesting should not overlap (just like 2 macro definitions should not overlap).
Consider this code:
'nope' does not show in the compiler log, because it's in a false comp-if. But 'yep' shows, even if it is (from the keyword nesting) inside the false if. Somehow the EndMacro is finishing the CompilerIf as well.

Code: Select all

#PBCONST = 0

Macro BLOCK_START
  CompilerIf (#PBCONST= 1)
    CompilerWarning "nope"
EndMacro
  
CompilerWarning "yep"

Macro BLOCK_END
CompilerEndIf
EndMacro


BLOCK_START 
Debug "some code" 
BLOCK_END 

; should expand to
;
; #PBCONST = 0
; 
; CompilerIf (#PBCONST= 1)
; Debug "some code" 
; CompilerEndIf
We had a similar discussion just some time ago, where Freak explained something about that IIRC.
#NULL
Addict
Addict
Posts: 1364
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Macros

Post by #NULL »

#NULL wrote: Tue Sep 07, 2021 1:48 pm I think the CompilerIf is evaluated while parsing the macro body, so the resulting macro content doesn't contain a CompilerIf anymore.
Scrap that. What I said above is probably all wrong :P
The compiler-directives are looked at only at the macro evaluation site, after the evaluation.
'yep' is printed first, then 'here' is printed, and 'nope' is not.

Code: Select all

Macro BLOCK_START
  CompilerWarning "here"
  CompilerIf 0
    CompilerWarning "nope"
EndMacro
  
CompilerWarning "yep"
BLOCK_START

And as stargate explained, BLOCK_END is in a false compilerif, so the compiler doesn't look at or into it and keeps looking only for a bare CompilerEndIf, which it doesn't find.
#NULL
Addict
Addict
Posts: 1364
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Macros

Post by #NULL »

STARGÅTE wrote: Tue Sep 07, 2021 1:46 pm One can argue, that the compiler can expand the macro but ignore all lines from that macro except a CompilerEndIf. But this can generate trouble if more CompilerIf statements are inside the macro itself, right?
I think that would get weird quickly. Should it find its CompilerIf here, even though the Macro shouldn't not be defined in the first place?

Code: Select all

CompilerIf 0
  Macro cend
    CompilerEndIf
  EndMacro
  cend
BTW it compiles fine with 'CompilerIf 1' :lol: because macro cend is defined and also evaluated.
Olli
Enthusiast
Enthusiast
Posts: 421
Joined: Wed May 27, 2020 12:26 pm

Re: Macros

Post by Olli »

If not already told, I remember there is a priority between macros and compiler directives. I think it is as below (compiler directives are not nestable in macros) :

Code: Select all

CompilerIf 0 ; <-- set 0 to 1 to change display.

Macro mac1(arg)
 debug arg
EndMacro

CompilerElse

Macro mac1(arg)
 messageRequester("", arg)
EndMacro

CompilerEndIf

mac1("Hello world")
Thank you Google search
Post Reply