Confusion around macros and variable expansion

Just starting out? Need help? Post your questions and find answers here.
Quin
Addict
Addict
Posts: 1122
Joined: Thu Mar 31, 2022 7:03 pm
Location: Colorado, United States
Contact:

Confusion around macros and variable expansion

Post by Quin »

Hi all,
I'm trying to make a helper function to automatically bind menu items to keyboard shortcuts on all platforms, but it's not working. It seems to be because I have a weird confusion about variable expansion in macros. Here's my code:

Code: Select all

Macro PBShortcut(_Key) : #PB_Shortcut_#_Key : EndMacro

; Get a bitmask of #PB_Shortcut constants from a key name in the format of, e.g. Ctrl+F
Procedure GetShortcutConstant(Shortcut$)
Protected Res, I, CurKey$
For I = 1 To CountString(Shortcut$, "+") + 1
CurKey$ = LCase(StringField(Shortcut$, I, "+"))
Select CurKey$
Case "ctrl" : Res | #PB_Shortcut_Control
Case "alt" : Res | #PB_Shortcut_Alt
Case "shift" : Res | #PB_Shortcut_Shift
Default : Res | PBShortcut(CurKey$)
EndSelect
Next
ProcedureReturn Res
EndProcedure

Procedure MenuShortcutItem(ItemID, Text$)
Protected Shortcut$
MenuItem(ItemID, Text$)
If Not FindString(Text$, Chr(9)) : ProcedureReturn : EndIf
Shortcut$ = Mid(Text$, FindString(Text$, Chr(9)))
AddKeyboardShortcut(#WndMain, GetShortcutConstant(Shortcut$), ItemID)
EndProcedure
When I run this, it tells me that #PB_Shortcut_CurKey$ is not a constant, which makes utterly no sense to me. If I'm passing it my variable, shouldn't it expand the value of the variable and substitute that? There are people much smarter and more experienced than me here so hoping someone can talk some sense into me :lol
Thanks in advance!
Andesdaf
User
User
Posts: 83
Joined: Sun Mar 22, 2009 2:53 pm
Location: GER, Saxony

Re: Confusion around macros and variable expansion

Post by Andesdaf »

no, the macro replaces the parameter by the given expression in the call without expanding it. See the second example in https://www.purebasic.com/documentation ... acros.html

You could try to get the shortcut value by using the runtime library.
User avatar
spikey
Enthusiast
Enthusiast
Posts: 749
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Re: Confusion around macros and variable expansion

Post by spikey »

This is the compile-time/run-time divide in action. The macro pre-processor operates in compile-time and has concluded by the start of run-time. It has no access to run-time context information. It operates literally on the text value of the expression supplied at the text level. (Think more autocorrect in a word processor than procedure call in a program). The expanded text literals are then supplied to the compiler to turn into opcodes along with the other source code in the file.

So in the example you give the macro will expand to the literal text '#PB_Shortcut_CurKey$' and the compiler doesn't recognise this when it arrives.

In this particular case you could probably map the ASCII code of the text to the #PB_Shortcut constant. See ASC(). EDIT: Actually a cursory look at the underlying constants suggests that the ASCII codes are used for these constants.
Last edited by spikey on Wed Nov 27, 2024 1:13 pm, edited 2 times in total.
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Re: Confusion around macros and variable expansion

Post by Psychophanta »

Please make a working code.
In your code #PB_Shortcut_CurKey$ is not defined.
Besides of it, you can not perform bit OR management with alfanumeric strings...
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
Quin
Addict
Addict
Posts: 1122
Joined: Thu Mar 31, 2022 7:03 pm
Location: Colorado, United States
Contact:

Re: Confusion around macros and variable expansion

Post by Quin »

spikey wrote: Wed Nov 27, 2024 11:19 am This is the compile-time/run-time divide in action. The macro pre-processor operates in compile-time and has concluded by the start of run-time. It has no access to run-time context information. It operates literally on the text value of the expression supplied at the text level. (Think more autocorrect in a word processor than procedure call in a program). The expanded text literals are then supplied to the compiler to turn into opcodes along with the other source code in the file.

So in the example you give the macro will expand to the literal text '#PB_Shortcut_CurKey$' and the compiler doesn't recognise this when it arrives.

In this particular case you could probably map the ASCII code of the text to the #PB_Shortcut constant. See ASC(). EDIT: Actually a cursory look at the underlying constants suggests that the ASCII codes are used for these constants.
Thanks so much, this was incredibly helpful! Reworked my code to this:

Code: Select all

; Get a bitmask of #PB_Shortcut constants from a key name in the format of, e.g. Ctrl+F
Procedure GetShortcutConstant(Shortcut$)
Protected Res, I, CurKey$
For I = 1 To CountString(Shortcut$, "+") + 1
CurKey$ = StringField(Shortcut$, I, "+")
Select CurKey$
Case "Ctrl" : Res | #PB_Shortcut_Control
Case "Alt" : Res | #PB_Shortcut_Alt
Case "Shift" : Res | #PB_Shortcut_Shift
Default : Res | Asc(CurKey$)
EndSelect
Next
ProcedureReturn Res
EndProcedure

Procedure MenuShortcutItem(ItemID, Text$)
Protected Shortcut$
MenuItem(ItemID, Text$)
If Not FindString(Text$, Chr(9)) : ProcedureReturn : EndIf
Shortcut$ = Mid(Text$, FindString(Text$, Chr(9)) + 1)
AddKeyboardShortcut(#WndMain, GetShortcutConstant(Shortcut$), ItemID)
EndProcedure
And all works as expected! :)
Thanks everyone for your answers.
Quin
Addict
Addict
Posts: 1122
Joined: Thu Mar 31, 2022 7:03 pm
Location: Colorado, United States
Contact:

Re: Confusion around macros and variable expansion

Post by Quin »

Never mind, it sadly doesn't work for all keys. F3 for example juss gives me the code for F... :(
Will I just need to put special cases for all of those?
User avatar
spikey
Enthusiast
Enthusiast
Posts: 749
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Re: Confusion around macros and variable expansion

Post by spikey »

Quin wrote: Wed Nov 27, 2024 2:43 pm Will I just need to put special cases for all of those?
You will need a special case yes, you'll need to detect the case where an F prefixed section is longer than 1 character. However, the #PB_Shortcut_Fn constants are sequential too, starting at 112. You could take the Val() of the suffix digits and add this to the base value of 111.
Quin
Addict
Addict
Posts: 1122
Joined: Thu Mar 31, 2022 7:03 pm
Location: Colorado, United States
Contact:

Re: Confusion around macros and variable expansion

Post by Quin »

Managed to come up with this, and all seems to work as expected! :)

Code: Select all

Procedure GetShortcutConstant(Shortcut$)
Protected Res, I, CurKey$
For I = 1 To CountString(Shortcut$, "+") + 1
CurKey$ = StringField(Shortcut$, I, "+")
If CurKey$ = "Ctrl" : Res | #PB_Shortcut_Control
ElseIf CurKey$ = "Alt" : Res | #PB_Shortcut_Alt
ElseIf CurKey$ = "Shift" : Res | #PB_Shortcut_Shift
ElseIf Left(CurKey$, 1) = "F" And Len(CurKey$) > 1 : Res | 111 + Val(Right(CurKey$, Len(CurKey$) - 1))
Else : Res | Asc(CurKey$) : EndIf
Next
ProcedureReturn Res
EndProcedure

Procedure MenuShortcutItem(ItemID, Text$)
Protected Shortcut$
MenuItem(ItemID, Text$)
If Not FindString(Text$, Chr(9)) : ProcedureReturn : EndIf
Shortcut$ = Mid(Text$, FindString(Text$, Chr(9)) + 1)
AddKeyboardShortcut(#WndMain, GetShortcutConstant(Shortcut$), ItemID)
EndProcedure
Thanks everyone!
User avatar
spikey
Enthusiast
Enthusiast
Posts: 749
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Re: Confusion around macros and variable expansion

Post by spikey »

You're welcome!
Post Reply