Sign in to follow this  
Followers 0
TheRauchster101

Tracing a recursion level error

24 posts in this topic

After creating a large program, I'm getting a recursion level exceeded error.

I know that this means I have a logical loop in the function, but the line that it's giving me the error for doesn't make sense:

If $BCPixelCheck1 = 0 AND $BCPixelCheck2 = 0 AND $BCPixelCheck3 = 0 Then

I was wondering how to implement a some sort of trace into the program to see where the code is actually looping, and method's to bypass it, as I want it to loop if certain circumstances are met.

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

After creating a large program, I'm getting a recursion level exceeded error.

I know that this means I have a logical loop in the function, but the line that it's giving me the error for doesn't make sense:

If $BCPixelCheck1 = 0 AND $BCPixelCheck2 = 0 AND $BCPixelCheck3 = 0 Then

I was wondering how to implement a some sort of trace into the program to see where the code is actually looping, and method's to bypass it, as I want it to loop if certain circumstances are met.

Its not this code that will give that error.

It has to be the call to an internal Function (FUNC).

Jos

Edited by Jos

Visit the SciTE4AutoIt3 Download page for the latest versions  - Beta files                                How to post scriptsource        Forum Rules
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites

Like Jos said, this gives a recursion exceeded error:

Hi()

Func Hi()
   Hi()
EndFunc

Recursion like this is tricky and you can only use it if you know the limits of what you are trying to implement. If your loop can occur once every 1-1000 times, then recursion is fine. If your loop can be called anywhere between 1 and 1 billion, but probably/maybe only just between 1-1000, then recursion will probably fail you eventually.

In many cases, recursion is a nice solution to a recursive problem. But even more cases, recursion is used inappropriately.

Share this post


Link to post
Share on other sites

Like Jos said, this gives a recursion exceeded error:

Hi()

Func Hi()
   Hi()
EndFunc

Recursion like this is tricky and you can only use it if you know the limits of what you are trying to implement. If your loop can occur once every 1-1000 times, then recursion is fine. If your loop can be called anywhere between 1 and 1 billion, but probably/maybe only just between 1-1000, then recursion will probably fail you eventually.

In many cases, recursion is a nice solution to a recursive problem. But even more cases, recursion is used inappropriately.

Thanks for the responses.

The line I quoted is the line error that it gave me in the error message box.

Is there a way to trace where the recursive error is coming from.

That particular PixelCheck I have limited to only run once every 5 seconds for 300 seconds total, which is why having the error code there doesn't make sense.

Share this post


Link to post
Share on other sites

Thanks for the responses.

The line I quoted is the line error that it gave me in the error message box.

Is there a way to trace where the recursive error is coming from.

That particular PixelCheck I have limited to only run once every 5 seconds for 300 seconds total, which is why having the error code there doesn't make sense.

A loop of PixelCheck does not sound like a recursive problem, so I'm curious why you opted for a recursive solution. A rewrite of code like:

Hi()

Func Hi()
   Hi()
EndFunc

into this is the best solution, because you'll never have to worry about recursion limits ever again.

While 1
   Hi()
WEnd

Func Hi()
EndFunc

As for tracing, etc., you'll have to write debug-level logging in your program (ConsoleWrite) or maybe a debugger like: . The easiest solution is probably take a very close look at your code.

On another note, this also causes recursion limits:

A()

Func A()
   B()
EndFunc

Func B()
   A()
EndFunc

Add Func C, Func D, Func E, etc. as necessary.

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

A loop of PixelCheck does not sound like a recursive problem, so I'm curious why you opted for a recursive solution. A rewrite of code like:

Hi()

Func Hi()
   Hi()
EndFunc

into this is the best solution, because you'll never have to worry about recursion limits ever again.

While 1
   Hi()
WEnd

Func Hi()
EndFunc

As for tracing, etc., you'll have to write debug-level logging in your program (ConsoleWrite) or maybe a debugger like: . The easiest solution is probably take a very close look at your code.

On another note, this also causes recursion limits:

A()

Func A()
   B()
EndFunc

Func B()
   A()
EndFunc

Add Func C, Func D, Func E, etc. as necessary.

Well, the pixelcheck isn't a recursive problem, but I don't know that many other ways around writing it. I'll admit I'm still a beginner level coder. While my coding can impressed the uninformed, to an expert I'm sure it'll look like child's play.

I do want the program to loop if certain conditions are met, and I guess that is the problem. It functions fine for upwards of 3-4 hours. But extensive periods of use have always resulted in this error.

If someone is willing to look at my code and let me know of another solution for writing it, I'd be happy to learn from a pro. It's far too big to paste into here. Here's a snippet of the code where the error seems to appear most frequently, though.

Func 1()
    If $XCounter > 0 Then
        Sleep($XTime)
        $XCounter = $XCounter - 1
        $PixelCheck1 = PixelGetColor($PixelCheck1X,$BCPixelCheck1Y)
        $PixelCheck2 = PixelGetColor($PixelCheck2X,$BCPixelCheck2Y)
        $PixelCheck3 = PixelGetColor($PixelCheck3X,$BCPixelCheck3Y)
        If $PixelCheck1 = 0 AND $PixelCheck2 = 0 AND $PixelCheck3 = 0 Then
            $XCounter = 36
            Call("2")
        Else
            Call("1")
        EndIf
    Else
        $XCounter = 36
        Call("Error")
        Call("Forfeit")
        Call("Exit")
    EndIf
EndFunc

Functions and variables are renamed, but you get the idea. And yes eventually the "2" function will loop through about 20 other functions then end back up at "1".

Edited by TheRauchster101

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

The term recursion is for me something like this:

MsgBox(0, "Fibonacci Numer", Fibonacci_r(10))

Func Fibonacci_r($f)
    If $f < 2 Then Return $f
    Return Fibonacci_r($f - 1) + Fibonacci_r($f - 2)
EndFunc

Each recursion function needs a termination condition otherwise the recursion stack will overflow.

Here If $f < 2 Then Return $f is the termination condition.

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

Your recursion problem is here:

Else
            Call("1")
        EndIf

Your If ... else statement calls the Function 1() inside itself if it doesn't find the pixel color you're looking for. It's probably not finding the colors over and over again and eventually the recursion level is reached.


If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post


Link to post
Share on other sites

Your recursion problem is here:

Else
            Call("1")
        EndIf

Your If ... else statement calls the Function 1() inside itself if it doesn't find the pixel color you're looking for. It's probably not finding the colors over and over again and eventually the recursion level is reached.

That why I put in the $XCounter - which is a Variable set at 36. The timer is set at 5000 (5 seconds) so that after 3 minutes (3 min = 180 seconds = 36*5). Each time it runs through and fails the pixel check, it should subtract one from the $XCounter. Once the $Xcounter hits 0 - It calls the error and exit functions. So, while there is a loop, it's not infinite. Should only happen for those 3 minutes.

That was my intent in that section anyway. Have I done something wrong?

Share this post


Link to post
Share on other sites

It appears to work correctly, unless somewhere else you're calling the function 1() and not returning from it correctly. Or, you're resetting the $Xcounter variable somewhere else. This part appears to be coded so that you'll avoid the recursion level from being reached, but it's not the right way to do it because you're not ending the Function and returning from it to unwind the recursion. I'm guessing that the other functions you're calling aren't returning correctly either, but have no way to verify this without more code.


If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post


Link to post
Share on other sites

It appears to work correctly, unless somewhere else you're calling the function 1() and not returning from it correctly. Or, you're resetting the $Xcounter variable somewhere else. This part appears to be coded so that you'll avoid the recursion level from being reached, but it's not the right way to do it because you're not ending the Function and returning from it to unwind the recursion. I'm guessing that the other functions you're calling aren't returning correctly either, but have no way to verify this without more code.

Well, I can send the entire code to a person if they want to look it over, but I doubt the entire thing would fit in a forum post here, as it's well over 25000 characters and nearly 900 lines.

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

Alrighty, it's been a while since I looked at this, and while I have a bit more knowledge in the AutoIT language now, I'm still getting stuck with the recursion error.

After reviewing the code, I removed all occurrences of any Func calling itself, and it is still giving me recursion errors at random time periods.

I believe it's as Manadal says:

On another note, this also causes recursion limits:

A()

Func A()

B()

EndFunc

Func B()

A()

EndFunc

Obviously way more complex than that, as I actually have about 50 different functions called, but the overall effect generated is a loop.

So, my question is, how do I break the loop and return to the main part of the script, then re-activate the start of the loop? I have a counter built in already that counts the number of full complete loops the program has made, ingeniously named $Counter.

Since the recursion error seems to happen after 250+ repeats, I can make the script stop at 200, but have no clue how to make it re-launch itself so that it can keep going.

And, are there other sites beyond the AutoIT forums that work with this sort of stuff? I'm willing to learn, but I'm struggling with some concepts. Like Return is one that I get but don't get at the same time.

Edited by TheRauchster101

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

You would do it this way:

While 1
    A()
Wend
 
Func A()
; do something here
B()
 
EndFunc
 
Func B()
; do something else here
 
EndFunc

This is only one way of doing it. The While...Wend loop will constantly call the A() function, the A() function will call B(), B() will return to A() when it's done, A() will finish doing what it needs and then returns back to the loop which will then loop around and call A() again. No recursions will happen because the functions are ending normally and not calling each other. This is just a simplistic demo of how to do something like this.

Edit: correcting the new board code screwups with code tags.

Edited by BrewManNH

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post


Link to post
Share on other sites

#14 ·  Posted (edited)

Alrighty, that makes sense. However, a quick monkey wrench being thrown in is that the script is activated by a HotKeySet, which calls a function that starts the entire thing.

I.E:

HotKeySet("{INS}", "Start")

Where Start calls everything else, and eventually loops back to Start.

Edited by TheRauchster101

Share this post


Link to post
Share on other sites

#15 ·  Posted (edited)

Func Start()
    While $Counter < 1000
        A()
    Wend
endfunc

Edited by BrewManNH

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post


Link to post
Share on other sites

Func Start()
    While $Counter < 1000
        A()
    Wend
endfunc

Awesome. I will give it a try and let you know. If it works, is there a thanks or rep button I can click to +1 you?

Share this post


Link to post
Share on other sites

Alrighty.... I've rewritten the code to look like this.

HotKeySet("{INS}", "First")
 
Func First()
While $RunCounter<5
  If $Starting=True Then
   $Starting=False
   Call("Start")
  ElseIf $Starting=False Then
   Call("Launch")
  EndIf
WEnd
EndFunc

Since I only want Start to run once, and Launch is the real looping point. I removed all references to Launch being called from any function as well, just to make sure that it can't loop outside of the While.

But what I don't understand is this.

Shouldn't that snippet of code END once $RunCounter is 5?

Because I just tested it, and it's still going at $RunCounter = 10....

Obviously I don't understand something.

I'm not complaining as I actually WANT it to keep looping.

But I like to understand my script too.

Share this post


Link to post
Share on other sites

#18 ·  Posted (edited)

Shouldn't that snippet of code END once $RunCounter is 5?

Not according to the actual data that's in that snippet. (No $RunCounter += 1 code)

But if $RunCounter is a Global variable, and its increased somewhere in the called code ... Yep.

Suggest you try dropping some ConsoleWrite()'s to see what actually happens. (Code flow and/or variable content changes.)

Edited by iEvKI3gv9Wrkd41u

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Share this post


Link to post
Share on other sites

#19 ·  Posted (edited)

Not according to the actual data that's in that snippet. (No $RunCounter += 1 code)

But if $RunCounter is a Global variable, and its increased somewhere in the called code ... Yep.

Suggest you try dropping some ConsoleWrite()'s to see what actually happens. (Code flow and/or variable content changes.)

I actually have it written longhand as:

$RunCounter=$RunCounter+1

Later on in the script, under a different call function.

But yes, the $RunCounter is increasing with each consecutive run like it should.

And yet again, this is still going on another test run where $RunCounter is currently at 7.

--EDIT--

Alrighty, I figured out why that was doing what it was doing. I had made a change in a #included script too, but hadn't saved it when I compiled the main file.

So now it's stopped when $RunCounter = 5.

So, now the question is. How do I automatically restart it without user input?

Edited by TheRauchster101

Share this post


Link to post
Share on other sites

I had made a change in a #included script too, but hadn't saved it when I compiled the main file.

Just in case, Optional Scite setting: save.all.for.build=1

So, now the question is. How do I automatically restart it without user input?

mmm, Think in that case your better of by not directly calling that function from a HotKeySet() call.

Alternative example:

global $HK_fIns = false
HotKeySet("{INS}", "_HK_INS")
func _HK_INS()
  $HK_fIns = true
endfunc
func wait()
  ;; some loop
  if $HK_fIns then
    $HK_fIns = false
    ;; do this
  endif
  ;; some other code.
endfunc

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0