Posts: 5
Threads: 3
Joined: Apr 2023
Reputation:
0
Hi,
if code is running inside a SUB, can I somehow get the SUB name?
This would be great to have for debugging or logging.
Posts: 1,510
Threads: 53
Joined: Jul 2022
Reputation:
47
Must run your code inside the QB64 IDE, and enable debug mode. ("Debug" menu has "Call Stack" and "Watch List" options.) Press [F7] or [F8] instead of [F5] to start your program inside the IDE. Aside from that, I don't know what to tell you because I have never used the IDE like that before.
Posts: 2,700
Threads: 124
Joined: Apr 2022
Reputation:
134
05-08-2023, 05:56 PM
(This post was last modified: 05-08-2023, 06:00 PM by bplus.)
If you can't figure out debug
DIM Shared Debug as Long
DIM Shared SubName$
in all your subs set that name SubName$ = ... in Sub (and maybe set to "main" or "" when exit sub?)
have a clause If Debug Then Print "Sub is ";SubName$
When Debug is set to -1 then it prints
If turn off, ie Debug = 0
then that clutter is removed.
Notice you can also comment out 'If Debug Then Print "Sub is ";SubName$
to pin down just the subs you are interested in.
Or Instead of print, try out MessageBox so dont mess up screen. Caveat - this does not work well in a fast loop!
b = b + ...
Posts: 529
Threads: 67
Joined: Apr 2022
Reputation:
11
05-08-2023, 06:03 PM
(This post was last modified: 05-08-2023, 07:10 PM by madscijr.)
(05-08-2023, 04:37 PM)thesolarcode Wrote: Hi,
if code is running inside a SUB, can I somehow get the SUB name?
This would be great to have for debugging or logging.
What mnrvovrfc said is probably right, but I'll share my caveman method of tracing my code and errors, when such features are not readily available, in case it helps...
I'm not saying this is the best method, but it has worked for me in the past.
Here is the general pattern which should give you the gist.
(You could use a global shared variable like bplus, I just opted to use local variables to preserve the state for nested calls, etc.)
I should probably look at the built-in debugging features, it can't hurt.
Code: (Select All) ' /////////////////////////////////////////////////////////////////////////////
Sub MySub(param1%, param2%, etc.)
Dim RoutineName As String : RoutineName = "MySub"
Dim sError As String : sError = ""
Dim sOperation As String : sOperation = "(variable declarations)"
Dim iLoop1%
Dim MyValue1%
Dim MyValue2%
(rest of declarations)
If len(sError)=0 then
for iLoop1% = param1% to param2%
sOperation = "MyValue1% = MyFunction$(iLoop1%, etc.)"
sError = MyFunction$(iLoop1%, etc.)
If len(sError) > 0 then exit for
next iLoop1%
End If
If len(sError)=0 then
(do next thing)
End If
Etc.
If Len(sError) > 0 Then
PrintDebugFile "Error in " & RoutineName & " at " & sOperation & ": " & sError
End If
End Sub ' MySub
' /////////////////////////////////////////////////////////////////////////////
Function MyFunction$(param3%, etc.)
Dim RoutineName As String : RoutineName = "MyFunction$"
Dim sError As String : sError = "" ' If routine failed, we return empty string, else return error message.
Dim sOperation As String : sOperation = "(variable declarations)"
Dim MyValue3%
(rest of declarations)
If len(sError)=0 then
sOperation = "if param3% = 0 then"
if param3% = 0 then
sError = "Error in " + RoutineName + ": param3% can't be 0"
end if
End If
If len(sError)=0 then
sOperation = "sError = MySubFunction$(MyValue3%, etc.)"
sError = MySubFunction$(MyValue3%, etc.)
End If
If len(sError)=0 then
(do something else)
(if some condition fails then put error message in variable sError)
End If
etc.
If Len(sError) > 0 Then
PrintDebugFile "Error in " & RoutineName & " at " & sOperation & ": " & sError
End If
MyFunction$ = sError
End Function ' MyFunction$
' /////////////////////////////////////////////////////////////////////////////
Function MySubFunction$(param4%, etc.)
Dim RoutineName As String : RoutineName = "MySubFunction$"
Dim sError As String : sError = ""
If len(sError)=0 then
'(if some condition fails then put error message in variable sError)
End If
etc.
MySubFunction$ = sError
End Function ' MySubFunction$
Posts: 1,507
Threads: 160
Joined: Apr 2022
Reputation:
116
Wouldn't the easiest way just be to assign a global variable for debug tracing?
DIM SHARED ProgFlow$
SUB Foo
ProgFlow$ = "Foo Start"
.... sub stuff
ProgFlow$ = "Foo Clean Exit"
END SUB
Posts: 1,510
Threads: 53
Joined: Jul 2022
Reputation:
47
(05-08-2023, 07:18 PM)SMcNeill Wrote: Wouldn't the easiest way just be to assign a global variable for debug tracing?
Code: (Select All) DIM SHARED ProgFlow$
SUB Foo
ProgFlow$ = "Foo Start"
.... sub stuff
ProgFlow$ = "Foo Clean Exit"
END SUB
Go further and write a QB64 program that creates a copy of QB64 source code that does this. It wouldn't be very difficult, easier because QB64PE (yet) doesn't support nested subprogram definitions. Only detect "SUB" or "FUNCTION" header and place a line right after it. Then set a flag indicating the processor is inside a subprogram, so it doesn't get confused with "main module" level code. Then when "END SUB" or "END FUNCTION is encountered put a line before that saying the subprogram is about to exit. Also have to check "EXIT SUB" and "EXIT FUNCTION" for it.
With "FUNCTION" get even fancier and even report what type it returns. "Entered function ''Zeroes'' which returns STRING."
It takes more effort to use such an utility, that's why some people expected the IDE to be able to do it.
Posts: 593
Threads: 44
Joined: Apr 2022
Reputation:
43
(05-08-2023, 07:18 PM)SMcNeill Wrote: Wouldn't the easiest way just be to assign a global variable for debug tracing?
DIM SHARED ProgFlow$
SUB Foo
ProgFlow$ = "Foo Start"
.... sub stuff
ProgFlow$ = "Foo Clean Exit"
END SUB
Pretty much what I do. Here is a snippet of code from a massive library I'm working on:
Code: (Select All) '+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__SET_AUTO_MOTION"
IF IUO__IS_OBJECT_VALID(Handle) = 0 THEN __ERROR "The object specified does not exist."
IF FPS <> __GLOBALFPS THEN
IF FPS < 1 OR FPS > GL_FPS.FPS THEN __ERROR "FPS must be between 1 and global FPS setting of" + STR$(GL_FPS.FPS) + "."
END IF
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
I have two global shared variables, __CURRENT_ROUTINE and __PREVIOUS_ROUTINE. I set __CURRENT_ROUTINE, perform my error checks and report any errors. If no errors exist I then set __PREVIOUS_ROUTINE so I have a trail from one routine to the next. __ERROR is used to report any errors.
Code: (Select All) SUB __ERROR (Message AS STRING) ' __ERROR |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Set screen to text mode and display error information passed in. |
'| |
'| __ERROR "Message" |
'| |
'| NOTE: Fatal error trap - halts program execution. |
'\_______________________________________________________________________________________________________________________________________________/
_FULLSCREEN _OFF ' turn off full screen if active
SCREEN 0, 0, 0, 0 ' set screen to pure text mode
CLS ' clear screen
PLAY "l64o3ao2ao1ao3ao2ao1ao3ao2ao1a" ' get developer's attention
COLOR 12, 0
PRINT ' print error message
PRINT " Game Library has encountered the following error condition:"
COLOR 15, 0
PRINT
PRINT " Error in routine: ";
COLOR 14, 0
PRINT __CURRENT_ROUTINE
COLOR 15, 0
PRINT " Previous routine: ";
COLOR 14, 0
PRINT __PREVIOUS_ROUTINE
COLOR 11, 0
PRINT
PRINT " "; Message
COLOR 7, 0
_KEYCLEAR ' clear all key buffers
END ' terminate with "Press any key to continue..."
END SUB
Software and cathedrals are much the same — first we build them, then we pray.
QB64 Tutorial
Posts: 2,700
Threads: 124
Joined: Apr 2022
Reputation:
134
05-09-2023, 03:34 PM
(This post was last modified: 05-09-2023, 03:37 PM by bplus.)
Yeah so who needs Debug of IDE? ;-))
DIYD = Do It Yourself Debug
Way more fun because you programmed it yourself so you know how it's supposed to work, supposedly ;-))
b = b + ...
Posts: 5
Threads: 3
Joined: Apr 2023
Reputation:
0
Thanks for all the ideas.
I wanted to do something like this:
SUB ApiOne
logging "start"
...
logging "end"
END SUB
But without adding the sub names into all the code.
Thinking about some simple preprocessor that could inject the sub names automatically.
For example if we have:
logging "$SUBNAME$: start"
it would be replaced with:
logging "ApiOne: start"
Soooo, how hard is it to implement a simple preprocessor?
Posts: 2,700
Threads: 124
Joined: Apr 2022
Reputation:
134
(05-10-2023, 03:16 PM)thesolarcode Wrote: Thanks for all the ideas.
I wanted to do something like this:
SUB ApiOne
logging "start"
...
logging "end"
END SUB
But without adding the sub names into all the code.
Thinking about some simple preprocessor that could inject the sub names automatically.
For example if we have:
logging "$SUBNAME$: start"
it would be replaced with:
logging "ApiOne: start"
Soooo, how hard is it to implement a simple preprocessor?
How about you make a template to copy/paste into a new sub and after you have a name copy/paste that into the template.
You could also write some code to read your bas files and insert stuff right after Sub/Function definition and just before End Sub/Function but then you have to direct all Exit Subs... to the end so maybe a line label in template?
Wait would a line label in a sub need a unique name from the entire program of just in the sub? Don't know... sounds like a fun little experiment... stay tuned.
b = b + ...
|