Occasional stack overflow - what gives?

Can someone please tell me what causes a stack overflow? The thing that confuses me, is it doesn’t happen all the time. I can run my script several times without a prob’, then suddenlt, out of the blue I get a Stack Overflow eror. Is it a memory issue? I’ve tried cleaning-up the script as much as possible, and even tried script debugger, but I don’t think I know how to use SD well enough. Maybe if I know the cause of a Stack Overflow, I’ll be able to fix the problem.
MUCH Thanks in advance,
-G

I guess it’d be easier to help me if you could run the script, but like I said it may take a few runs through before an error occurs.

property mistakeliststring : ""
property practiceletterstring : ""
property practiceLetter : ""
property practiceList : ""
property wordCheck : " "
property mistakeList : " "
property ALetter : " "
property startTime : ""
property timeDifference : ""
property endTime : ""
property theTypedWord : ""
property wpm : 0
property chosenWord : ""
property number_correct : 0
property wpmstring : ""
property avNumWords : 0
--*************************
reset()
--*************************
to reset()
	set startTime to 0
	set endTime to 0
	set timeDifference to 0
	set number_correct to 0
	set wpm to 0
	set wpmstring to ""
	set practiceList to ""
	set practiceLetter to ""
	set mistakeList to ""
	set mistakeliststring to ""
	set practiceletterstring to ""
	set wordCheck to ""
	set ALetter to ""
	set startTime to ""
	set theTypedWord to ""
	set chosenWord to ""
	set wpmstring to ""
	set avNumWords to 0
	-----------------------------------------------	
	display dialog "GassyTypingPractice 1.0" & return & return & "Type the letters above the text area," & return & "as in the example below." & return & return & "example" default answer "example" buttons {"Cancel", "START"} default button "START" with icon 1
	PreSet()
end reset
--*************************
to PreSet()
	if timeDifference > 4 then
		showscoreEnd()
	end if
	try
		set practiceLetter to some item in practiceList
	end try
	getlevel()
end PreSet
--*************************
to getlevel()
	if wpm is less than 6 then
		set the_list to {"asdf", "afds", "sfad", "dsfa", "jkls", "ljka", "jaks", "lfks", "sjal", "fjsl", "lkds", "kjfd", "alsk", "ajdl", "jlfs"}
	else if wpm is less than 11 then
		set the_list to {"ahsdf", "qazw", "azqx", "wsxe", "sxwc", "edcr", "dcev", "rfve", "fvrc", "tgvf", "yhbn", "ujni", "jnum", "ujmi", "jmun", "ikjo", "lkjm", "afhds", "sfagd", "hdsfa", "jklgs", "lhjka", "jhaks", "lfksg", "sjhal", "gfjsl", "lkdsh", "kjfgd", "ahlsk", "ajdgl", "jhlfs", "ghfjd", "flash", "glads", "ksgha", "lhgsj"}
	else if wpm is less than 16 then
		set the_list to {"stew", "huge", "polite", "ploy", "swat", "rough", "read", "quiet", "pride", "dead", "deal", "kill", "hurt", "shirt", "justify", "height", "flush", "they", "used", "pout", "proud", "trout", "great", "gift", "queer", "iraq", "wade", "quote", "thought", "kite", "pike", "lake", "fake", "freak", "treat", "trees", "rush", "trash", "dry", "droop", "pair", "fright", "fryer", "flight", "spite", "trout", "read", "seed", "dear", "poke", "speed", "seed", "ripe", "quilt", "dark", "dusk", "yard", "party", "dirty", "flirt", "flower", "flour", "squirt", "square", "jail", "jerk", "jimmy", "jewish"}
	else if wpm is less than 21 then
		set the_list to {"hello", "Gary", "button", "laxative", "next", "xerox", "extreme", "excited", "house", "tonight", "cigarette", "kitchen", "Milwaukee", "Wisconsin", "Franklin", "penny", "nickle", "dime", "quarter", "dollar", "king", "queen", "jack", "ten", "nine", "eight", "seven", "six", "five", "four", "three", "two", "one", "zero", "after", "army", "apple", "ace", "blue", "brown", "red", "yellow", "rhyme", "green", "black", "white", "iraq", "iran", "bingo", "beatles", "ghost", "sign", "president", "exit", "enter", "door", "window", "zipper", "jazz", "buzzard", "blizzard", "century", "circus", "days", "enough", "elephant", "echo", "flight", "french", "hat", "hour", "ink", "itch", "jinx", "jerk", "lamp", "listen", "mouth", "mice", "market", "never", "knife", "north", "opera", "ounce", "park", "punt", "resist", "run", "rope", "sit", "shelf", "start", "store", "square", "time", "that", "them", "try", "under", "above", "uncle", "usher", "vice", "vote", "work", "when", "winter", "wonderful", "year", "typist", "television", "lazy", "guitar", "water", "sugar", "orange", "rake", "injury", "tissue", "empty", "automobile", "crazy", "happiness", "munch", "crunch", "examine", "burn", "verse", "over", "squint", "squeeze"}
	else
		set the_list to {"Hello, how are you today?", "Gary is a very cool dude.", "Button your flannel shirt.", "The fireplace burned brightly.", "Tonight is all we have.", "Smoke gets in your eyes.", "Let's paint the kitchen purple!", "Milwaukee is the beer capitol.", "Wisconsin is the dairy state.", "Franklin is very near to Milwaukee.", "A penny earned isn't much.", "A nickle equals five cents.", "Two nickles equal one dime.", "I'll have a quarter pounder.", "Can I have a dollar?", "king Henry had headless wives!", "A queen bee is huge!", "Jack sprat ate no fat.", "Ten people ran that way.", "Nine comes right after eight.", "Eight tacos with hot sauce.", "Six feet deep sounds good.", "Five threes is a Yahtzee!", "The dog wants to go for a walk.", "Three little pigs arrested me.", "Two more for the road!", "One is the loneliest number.", "Here's your prize.", "The aspirin is in the medicine cabinet.", "Our army is much bigger.", "Don't eat the poison apple.", "The ace is the highest.", "The grey sky turned blue.", "I want to drive the van next.", "Do my eyes look red?", "Your yellow shirt is dirty.", "Axe doesn't rhyme with bird.", "Is the lawn green yet?", "Black widow spiders scare me.", "Reggie White sacked the quarterback!", "Iraq is nice to visit.", "Iran harbors terrorists no more.", "Bob Dylan wrote excellent lyrics.", "Casper is a friendly ghost.", "The sign is located above the door.", "Please vote for president Bush.", "The exit is that way.", "Don't enter while I'm showering.", "We need new carpeting in here.", "Wash the window with ammonia.", "My zipper is stuck again!", "Jazz music can relax me.", "The buzzard circled our camp.", "This blizzard better stop soon!", "That happened nearly a century ago.", "Circus clowns drive little cars.", "Forty days and forty nights.", "That's enough spaghetti for me.", "Elephants can remember very well.", "Do you hear an echo?", "Flight was a great invention.", "French people hate french fries.", "This knife isn't sharp anymore.", "A compass always points north.", "Good Opera hurts my ears.", "How many ounces was that?", "Don't park in my spot!", "Please don't punt the ball.", "How can you resist me?", "Walk, don't run in here.", "Is that rope tied securely?", "Just sit down and watch.", "The shelf can't hold that.", "Let's start all over again.", "Squirrels store all their nuts.", "Squares can't fit into circles!", "Time is on my side.", "It takes a lot to laugh, but it takes a train to cry.", "Some are smears, and some are spots.", "Al Gore invented the internet.", "Still crazy after all these years.", "Megan wishes she could be cool like Gary.", "Go fly a kite.", "Do chickens have lips?"}
	end if
	repeat 10 times
		set chosenWord to some item of the_list
		set chosenWordi to items in chosenWord
		if practiceList is "" then exit repeat
		if practiceLetter is in chosenWordi then
			set practiceletterstring to "It's time to practice the letter " & practiceLetter & "."
			exit repeat
		else
			set practiceletterstring to ""
		end if
	end repeat
	giveWord()
end getlevel
--*************************
to giveWord()
	set numLetters to count of chosenWord
	set avNumWords to numLetters / 5
	set startTime to current date
	
	set {theTypedWord, button_pressed} to {text returned, button returned} of (display dialog "GassyTypingPractice 1.0" & return & return & wpmstring & " words per minute." & return & ¬
		practiceletterstring & return & return & chosenWord default answer "" buttons {"Cancel", "PAUSE", "NEXT"} default button "NEXT" with icon 1)
	if button_pressed is "PAUSE" then
		showscore()
	else if theTypedWord ? chosenWord then
		getbadletter()
	end if
	goodAnswer()
end giveWord
--*************************
to goodAnswer()
	set endTime to current date
	set timeDifference to timeDifference + (endTime - startTime) / 60
	set number_correct to number_correct + avNumWords as string
	try
		set wpm to (number_correct / timeDifference)
		set wpm2 to (number_correct / timeDifference) as string
	end try
	if (count of wpm2) > 3 then
		set wpmstring to items 1 thru 4 of wpm2 as string
	else if (count of wpm2) < 4 then
		set wpmstring to wpm2 as string
	end if
	PreSet()
end goodAnswer
--*************************
to getbadletter()
	beep 1
	set oops to theTypedWord as text
	set typedletters to items in oops
	repeat with ALetter in chosenWord
		if typedletters does not contain ALetter and ¬
			ALetter is not in mistakeList and ¬
			ALetter is not in {" ", ",", ".", "'", "?", "!", ""} then
			set mistakeList to mistakeList & " " & ALetter
			set practiceList to practiceList & ALetter
		end if
	end repeat
	badDialog()
end getbadletter
--*************************
to badDialog()
	if theTypedWord is "" then
		set theTypedWord to "No Text Was Entered!"
	end if
	set {theTypedWord, button_pressed} to {text returned, button returned} of (display dialog "GassyTypingPractice 1.0" & return & return & wpmstring & return & "OOPS!---> " & theTypedWord & return & return & chosenWord default answer "" buttons {"Cancel", "PAUSE", "NEXT"} default button "NEXT" with icon 2)
	if button_pressed is "PAUSE" then
		showscore()
	else if theTypedWord ? chosenWord then
		getbadletter()
	end if
	goodAnswer()
end badDialog
--*************************
to showscore()
	if mistakeList ? "" then
		set mistakeliststring to "Some letters you need to practice:
		" & mistakeList
	end if
	beep 3
	if wpm = 0 then
		set wpmstring to "You didn't type anything!"
	end if
	
	set the_result to button returned of (display dialog "GassyTypingPractice 1.0" & return & return & ¬
		"You're typing " & wpmstring & " words per minute." & return & ¬
		mistakeliststring & return buttons {"Cancel", "Start Over", "Continue"} default button 3 with icon 1)
	if the_result is "Continue" then
		PreSet()
	else
		reset()
	end if
end showscore
--*************************
to showscoreEnd()
	beep 3
	display dialog "GassyTypingPractice 1.0" & return & return & ¬
		"You typed " & wpmstring & " words per minute." & return & ¬
		mistakeliststring & return buttons {"Cancel", "Let's do that again!"} default button 2 with icon 0
	reset()
end showscoreEnd

I just noticed that my last post doesn’t compile because there are 3 or 4 places where a “Does Not Equal” sign as replaced with a question mark after it was submitted. It should work fine if you put it in manually durring compile.

OK, this one is going to be tricky - but I guess you knew that already, didn’t you? :slight_smile:

A stack overflow is a basic memory error - you’ve asked the script to do more than it can keep track of. They typically happen in repeat loops where inside the loop you ask it to do something that calls itself.

It took me a couple of times to reproduce the problem - for some reason I couldn’t get past the “Please vote for president ” word :wink:

The problem in this case is the basic script flow. If you walk through the script (and assume you type the word correctly) you’ll find it goes something like this:

run → reset → PreSet → getlevel → giveWord → goodAnswer → PreSet

However, at this point the script has to keep track of your path back to the beginning. The ‘PreSet’ handler your’re in now is not the same PreSet handler at step 2. What’s worse is that, assuming you keep typing correctly, each PreSet will append:

PreSet → getlevel → giveWord → goodAnswer → PreSet

to the stack trace, ad infinitum.

In other words, none of your handlers ever end, they just keep calling other handlers.

To fix it you need to restructure your script such that the handlers return to a master handler, like:

on run
  reset()
  set done to false
  PreSet()
  set nextWord to getlevel() -- have 'getlevel' return the next word rather than calling giveWord itself
  repeat until done is true
     set userResponse to giveWord (nextWord) -- pass the variable into giveWord so it knows what word to use, and pass pack the result
     if userResponse = "QUIT" then
      set done to true
     else if userResponse = "PAUSE" then
       showscore()
    else if userResponse = "" then
       badDialog()
    else if userResponse is not equal to nextWord then
       getbadletter()
    else
      goodAnswer() -- do the calcs
      PreSet() -- preset
      set nextWord to getlevel() -- choose the next word
    end if
   end repeat
   showscoreEnd()
end run

Note that the above code will not directly translate into your current code - you’ll need to move some of the functionality around, but the basic idea is to have a single handler that repeatedly calls the others rather than having each handler call the next one without truly ending itself.

Hope this helps.

Thank you, Thank you, thank you! My original code, while sloppy as he**, was one long Repeat routine, and I didn’t have any problems. but somewhere along the line I decided a bunch of sub-routines would clean- up the script. I never connected the problem with the way I structured my script. From what I gather in your post, I should go back to the one - single repeat routine, while keeping the latest (ie: neater) syntax in place. I’ll give it a try and see what happens. I’m soooo greatful for your help. I feel guilty everytime I post that g-forsaken script on this site.
Thanks Again,
-G

B.T.W… Why do some cripts show-up on this site looking like I’m viewing it through the script editor on my 'puter, while mine show-up looking like I pasted it from a bad text editor? Do I have to chage the font size & color for each individaual Variable, comment, etc,?

They probably used John’s “Convert Script to Markup Code”: