Page 1 of 2

Expanded View of Macros

Posted: Sun Nov 10, 2013 7:42 am
by TI-994A
Hello everyone. Firstly, sincere apologies if this has been asked before, although a quick search didn't yield any relevant results.

Is there any way, within the PureBasic Editor, to expand and view macros in place? It would improve readability during debugging, especially in the case of longer, more elaborate macros.

Thank you. :)

Re: Expanded View of Macros

Posted: Sun Nov 10, 2013 11:40 am
by luis
No AFAIK.

When I want to check how the macro is expanded, I put an error in it (a superfluous char at the end usually).

http://www.purebasic.fr/english/viewtop ... 56#p376056

Re: Expanded View of Macros

Posted: Sun Nov 10, 2013 1:47 pm
by TI-994A
luis wrote:No AFAIK.

When I want to check how the macro is expanded, I put an error in it (a superfluous char at the end usually).
Hi luis; thanks for your answer and the tip. It's a real pity as my code is usually littered with macros, and reading source listings without them expanded could be quite tiresome.

I'm sure that others face this problem as well, and if someone has found any kind of solution, please do share. :)

Re: Expanded View of Macros

Posted: Mon Nov 11, 2013 8:44 am
by BorisTheOld
TI-994A wrote:It's a real pity as my code is usually littered with macros, and reading source listings without them expanded could be quite tiresome.
Surely the purpose of macros is to hide the messy details and to make the code more readable? :)
TI-994A wrote:I'm sure that others face this problem as well, and if someone has found any kind of solution, please do share.
When I first create a macro, I test it by putting a garbage character at the end of the statement that uses it. The pop-up error message contains the expanded code. After that, I never want to see the underlying PB code again.

Re: Expanded View of Macros

Posted: Mon Nov 11, 2013 11:28 am
by luis
BorisTheOld wrote: When I first create a macro, I test it by putting a garbage character at the end of the statement that uses it. The pop-up error message contains the expanded code.
Wow, this is really a GREAT tip unheard of ! :D

Re: Expanded View of Macros

Posted: Mon Nov 11, 2013 1:00 pm
by TI-994A
BorisTheOld wrote:Surely the purpose of macros is to hide the messy details and to make the code more readable? :)
Hello BorisTheOld. Personally, I believe that macros are more for reducing repetitive tasks than for increasing readability. A laconic listing is just a bonus, but debugging such code can be very tiresome.
BorisTheOld wrote:...After that, I never want to see the underlying PB code again.
BorisTheOld wrote:...We use a simple text substitution macro facility in our code generator software...
In another thread (link), you mentioned using some in-house tool for expanding macros. Seems that you too have a need for such a utility, and perhaps you'd be kind enough to share that with us? :D

Re: Expanded View of Macros

Posted: Mon Nov 11, 2013 10:18 pm
by BorisTheOld
TI-994A wrote:Hello BorisTheOld. Personally, I believe that macros are more for reducing repetitive tasks than for increasing readability. A laconic listing is just a bonus, but debugging such code can be very tiresome.
But, only if you plan to write code that has bugs in it. A toolbox full of macros, modules, and classes, essentially eliminates coding errors.
TI-994A wrote:In another thread (link), you mentioned using some in-house tool for expanding macros. Seems that you too have a need for such a utility, and perhaps you'd be kind enough to share that with us? :D
There are macros, and then there are macros. We use different types for different purposes.

The text substitution macros, mentioned in the link, are used when writing templates for the code generators in our Data Dictionary software. We use a separate class of macros when writing actual PB code. These macros add clarity to the code and provide standard BASIC features that are missing from PB. In particular, supporting OOP without getting bogged down in PB syntax.

The following trivial statements in a Data Dictionary script:

Code: Select all

  {for} iFromPtr {from} 1 {to} 19
    {if} {getmid}sRegistrationNumber, iFromPtr, 1{/getmid} <> {c}CHAR_MINUS {then}
      {incr}iToPtr{/incr}
      {setmid}sWork, iToPtr, 1{setto}{getmid}sRegistrationNumber, iFromPtr, 1{/getmid}{/setmid}
    {/if}
  {/for}
will produce the following source code for PowerBasic:

Code: Select all

  For iFromPtr = 1 To 19
    If Mid$(sRegistrationNumber, iFromPtr, 1) <> $cCHAR_MINUS Then
      Incr iToPtr
      Mid$(sWork, iToPtr, 1) = Mid$(sRegistrationNumber, iFromPtr, 1)
    End If
  Next
but will produce the following source code for PureBasic, which is readable:

Code: Select all

  For iFromPtr = 1 To 19
    If MidGet(sRegistrationNumber, iFromPtr, 1) <> #cCHAR_MINUS Then
      Increment(iToPtr)
      MidSet(sWork, iToPtr, 1, MidGet(sRegistrationNumber, iFromPtr, 1))
    EndIf
  Next
which, with the application of our PB macros, reduces to the following PB code, which is not so readable:

Code: Select all

  For iFromPtr = 1 To 19
    If Mid(sRegistrationNumber, iFromPtr, 1) <> #cCHAR_MINUS
      iToPtr = iToPtr + 1
      gloApp\subMidSet (@sWork, Len(sWork), iToPtr, 1, Mid(sRegistrationNumber, iFromPtr, 1), 1)
    EndIf
  Next

Re: Expanded View of Macros

Posted: Tue Nov 12, 2013 8:59 am
by TI-994A
BorisTheOld wrote:But, only if you plan to write code that has bugs in it. A toolbox full of macros, modules, and classes, essentially eliminates coding errors.
Hello again. Clearly, you're a much better coder, because regardless of the bevy of libraries and macros at my disposal, I'm still prone to making coding errors. :)
BorisTheOld wrote:There are macros, and then there are macros. We use different types for different purposes.

Code: Select all

  {for} iFromPtr {from} 1 {to} 19
    {if} {getmid}sRegistrationNumber, iFromPtr, 1{/getmid} <> {c}CHAR_MINUS {then}
      {incr}iToPtr{/incr}
      {setmid}sWork, iToPtr, 1{setto}{getmid}sRegistrationNumber, iFromPtr, 1{/getmid}{/setmid}
    {/if}
  {/for}
That's literally a whole new command set; don't see how it promotes readability.

Granted, you might have your reasons for using such mnemonics, but personally, I believe that proper use of macros should result in highly terse code, instead of a more verbose and cryptic one.

In any case, in the same spirit of triviality, here's the above script, in PureBasic form: :lol:

Code: Select all

 sWork = ReplaceString(sRegistrationNumber, #cCHAR_MINUS, "")

Re: Expanded View of Macros

Posted: Tue Nov 12, 2013 12:08 pm
by PB
> I believe that macros are more for reducing repetitive tasks than for increasing readability

It depends. Consider these two macros that I use in all my apps:

Code: Select all

Macro KeyIsDown(key)
  GetAsyncKeyState_(key) & $8000
EndMacro

Macro KeyIsUp(key)
  GetAsyncKeyState_(key)=0
EndMacro
These totally increase readability a million-fold. I don't even have
to explain to you what they do, because they're so obvious. :)

Someone seeing "GetAsyncKeyState_(key) & $8000" and who isn't
familiar with Windows, will have no idea what that does; but when
seeing it as my macro, they know instantly.

Re: Expanded View of Macros

Posted: Tue Nov 12, 2013 3:23 pm
by Little John
TI-994A wrote:In any case, in the same spirit of triviality, here's the above script, in PureBasic form: :lol:

Code: Select all

 sWork = ReplaceString(sRegistrationNumber, #cCHAR_MINUS, "")
Dear TI-994A, that's far too simple!
Everybody can do it that way. :mrgreen:

Re: Expanded View of Macros

Posted: Tue Nov 12, 2013 3:33 pm
by BorisTheOld
TI-994A wrote:
BorisTheOld wrote:There are macros, and then there are macros. We use different types for different purposes.

Code: Select all

  {for} iFromPtr {from} 1 {to} 19
    {if} {getmid}sRegistrationNumber, iFromPtr, 1{/getmid} <> {c}CHAR_MINUS {then}
      {incr}iToPtr{/incr}
      {setmid}sWork, iToPtr, 1{setto}{getmid}sRegistrationNumber, iFromPtr, 1{/getmid}{/setmid}
    {/if}
  {/for}
That's literally a whole new command set; don't see how it promotes readability.
Like I said, there are macros, and then there are macros. The above example has its origins in code written over 35 years ago, when we were converting large Assembler applications to COBOL, then later from COBOL to Visual Basic, then from VB to PowerBasic, and now from PowerBasic to PureBasic. Along the way, the same in-house macro processor has been used to revert some of our code back to Assembler, and even to Pascal. When combined with the specifications in our Data Dictionary, these low level scripts can be used to generate code that is untouched by human hand. But most importantly, they create bug free code and provide a mechanism for filling gaps in the programming language.

Since our applications exist as specifications in a database, the final code is only a convenience for customers, or others, who wish to have a copy of the source. And it's at this level of abstraction that we make use of other language-based macros to simplify or clarify the code. The type of macros that PB describes.

So that the following code:

Code: Select all

PrivateSubroutine(XX2822Attach) (ByMe)
  If NotObject(Me\proPanelXX2822)
    Me\proPanelXX2822 = CreateObject(PanelItem)
    Set(Me\proPanelXX2822, exoParent, Me\proAppPanel)
    Set(Me\proPanelXX2822, exsTabText, "Site Options")
    SetCallBack(Me\proPanelXX2822, expCBDesign, XX2822Design)
    ObjectCall(Me\proPanelXX2822, Build) ()
  Else
    ObjectCall(Me\proPanelXX2822, Show) ()
  EndIf
EndSubroutine
is easier to understand than:

Code: Select all

Procedure clsDvsML06_subXX2822Attach (*Self.strDvsML06)
  If *Self\proPanelXX2822 = 0
    *Self\proPanelXX2822 = clsPanelItem_funCreate()
    *Self\proPanelXX2822\setexoParent(*Self\proAppPanel)
    *Self\proPanelXX2822\setexsTabText("Site Options")
    *Self\proPanelXX2822\setexpCBDesign(1, @clsDvsML06_subXX2822Design())
    *Self\proPanelXX2822\setexpCBDesign(2, *Self)
    *Self\proPanelXX2822\subBuild ()
  Else
    *Self\proPanelXX2822\subShow ()
  EndIf
EndProcedure

Re: Expanded View of Macros

Posted: Thu Nov 14, 2013 6:37 am
by TI-994A
PB wrote:

Code: Select all

Macro KeyIsDown(key)
  GetAsyncKeyState_(key) & $8000
EndMacro

Macro KeyIsUp(key)
  GetAsyncKeyState_(key)=0
EndMacro
These totally increase readability a million-fold. I don't even have
to explain to you what they do, because they're so obvious. :)
Hi PB. Firstly, lovely macros; clear and concise, and a very good example of increased readability.
PB wrote:Someone seeing "GetAsyncKeyState_(key) & $8000" and who isn't
familiar with Windows, will have no idea what that does; but when
seeing it as my macro, they know instantly.
Yes, although for such one-liners, simple comments would suffice. Furthermore, for added clarity, brevity, and functionality, it's better to encapsulate API functions into procedures, for example:

Code: Select all

Procedure KeyIsDown(vKey)
  If GetAsyncKeyState_(vKey)
    ProcedureReturn GetAsyncKeyState_(vKey) & $8000
  EndIf
EndProcedure
Perhaps it simply boils down to personal preferences. :)

Re: Expanded View of Macros

Posted: Thu Nov 14, 2013 6:39 am
by TI-994A
BorisTheOld wrote:... The above example has its origins in code written over 35 years ago, when we were converting large Assembler applications to COBOL, then later from COBOL to Visual Basic, then from VB to PowerBasic, and now from PowerBasic to PureBasic. ...
Hello again BorisTheOld. Point noted, although you're talking about ancient code-conversion macros, when we're discussing code-substitution macros within PureBasic. :lol:
BorisTheOld wrote:

Code: Select all

PrivateSubroutine(XX2822Attach) (ByMe)
  If NotObject(Me\proPanelXX2822)
    Me\proPanelXX2822 = CreateObject(PanelItem)
    Set(Me\proPanelXX2822, exoParent, Me\proAppPanel)
    Set(Me\proPanelXX2822, exsTabText, "Site Options")
    SetCallBack(Me\proPanelXX2822, expCBDesign, XX2822Design)
    ObjectCall(Me\proPanelXX2822, Build) ()
  Else
    ObjectCall(Me\proPanelXX2822, Show) ()
  EndIf
EndSubroutine
is easier to understand than:

Code: Select all

Procedure clsDvsML06_subXX2822Attach (*Self.strDvsML06)
  If *Self\proPanelXX2822 = 0
    *Self\proPanelXX2822 = clsPanelItem_funCreate()
    *Self\proPanelXX2822\setexoParent(*Self\proAppPanel)
    *Self\proPanelXX2822\setexsTabText("Site Options")
    *Self\proPanelXX2822\setexpCBDesign(1, @clsDvsML06_subXX2822Design())
    *Self\proPanelXX2822\setexpCBDesign(2, *Self)
    *Self\proPanelXX2822\subBuild ()
  Else
    *Self\proPanelXX2822\subShow ()
  EndIf
EndProcedure
Not necessarily. With no knowledge of the macro parameter structures:

Code: Select all

Set(Me\proPanelXX2822, exoParent, Me\proAppPanel)
is in no way more understandable than:

Code: Select all

*Self\proPanelXX2822\setexoParent(*Self\proAppPanel)
And, if the original function names were a little less cryptic to begin with, such substitutions serve very little purpose. For example, if clsPanelItem_funCreate() were named something like createNewPanelItem():

Code: Select all

*Self\proPanelXX2822 = createNewPanelItem()
is just as readable as

Code: Select all

Me\proPanelXX2822 = CreateObject(PanelItem)
eliminating the need for a clarifying macro. :lol:

But, like I mentioned earlier, perhaps it just boils down to personal preferences. :)

Re: Expanded View of Macros

Posted: Thu Nov 14, 2013 6:44 am
by TI-994A
To reiterate, if anyone knows of a way, or has some utility that could expand PureBasic macros within the source listing, please do share.

Thank you. :D

Re: Expanded View of Macros

Posted: Thu Nov 14, 2013 9:02 am
by BorisTheOld
TI-994A wrote:Hello again BorisTheOld. Point noted, although you're talking about ancient code-conversion macros, when we're discussing code-substitution macros within PureBasic. :lol:
Actually, it's PB's macro feature which is antiquated. It's close to being non-existant. It would be a lot more useful if it had the capabilities of the MASM macro feature from 30 years ago, which forms the basis of our data dictionary scripting language.

New is not always better. :wink: