Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

Newcomers DBPro Corner / The goto command

Author
Message
TheComet
17
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 9th Dec 2011 16:23
I luv gotos



TheComet

nonZero
13
Years of Service
User Offline
Joined: 10th Jul 2011
Location: Dark Empire HQ, Otherworld, Silent Hill
Posted: 9th Dec 2011 18:38
lol, instant aneurysm. Very good illustration on the difficulty involved in debugging GOTO-enriched code...

...Scary thing is I still managed to debug it! "GOTO finishedgetimages" (line41) is referencing the label "finishedgetimage:"(line28).



... Is this proof of my severe case of NSL (No Social Life)? Likely...

TheComet
17
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 9th Dec 2011 19:21
Damn, didn't use enough goto...

TheComet

IanM
Retired Moderator
22
Years of Service
User Offline
Joined: 11th Sep 2002
Location: In my moon base
Posted: 9th Dec 2011 22:16
Hodgey
15
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 9th Dec 2011 22:28
I was about to say that .

I think writing goto code like the above is also quite annoying (I know that one may seem a bit exaggerated) even if there is only a couple of gotos.

zenassem
21
Years of Service
User Offline
Joined: 10th Mar 2003
Location: Long Island, NY
Posted: 10th Dec 2011 18:13
Anyone have a COMEFROM plugin?

The following is an example of a program in a hypothetical BASIC dialect with "COMEFROM" instead of "GOTO".

10 COMEFROM 40
20 INPUT "WHAT IS YOUR NAME? "; A$
30 PRINT "HELLO, "; A$
40 REM

The program (hypothetically) works by asking the user for their name, then greeting them with the same name, and continuing all over again. The instruction "REM" on line 40 is simply a NOP — the "COMEFROM" statement on line 10 causes a branch back to that line when execution reaches line 40, regardless of its contents.

http://en.wikipedia.org/wiki/COMEFROM



~ZENassem
TheComet
17
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 10th Dec 2011 21:41
Yes, and to top it off, let\'s all program in this language : http://tinyurl.com/4f6mt

TheComet

nonZero
13
Years of Service
User Offline
Joined: 10th Jul 2011
Location: Dark Empire HQ, Otherworld, Silent Hill
Posted: 11th Dec 2011 19:07 Edited at: 11th Dec 2011 19:08
Quote: " ... yur doin it rong! "


Might as well make it official...



Quote: " Anyone have a COMEFROM plugin? "


There's a product called "obfuscationgamedevelopmentkitversion1.1" scheduled for release in january 2012. It will include plugins for INTERCAL, FALSE and [brainf...] (see TheComet's link). It comes with an editor/compiler that will refuse to tell you which line an error occurred on if one occurs, but instead give you four possibilities to guess from. You will receive three "lifelines" per session to give you hints. Should you fail to correct the CORRECT error, your system will be crashed upon the next compile. This is to train you to think laterally.
As for the native "obfuscationcode", it is dead easy to learn. Here is the Hello World program:


"obfuscationgamedevelopmentkitversion1.1" also comes with a free 3D modelling app that will help bring your models to life by adding bright, sparkly colours to them over those dull metal textures we're all so bored with. A product like this could easily sell for $1.99 USD but we're offering it to you at a special launch price of $70-00 USD. What a bargain!


Xmas this year's gonna be great...to survive!

Agent
20
Years of Service
User Offline
Joined: 7th Sep 2004
Location: Sydney, Australia
Posted: 22nd Dec 2011 07:01 Edited at: 22nd Dec 2011 07:02
Quote: "If you can't see the GOTO and the label on-screen together, you're doing it wrong."


Quote: "...I see a new meme being born"


I'm totally claiming this meme. I said it first!:

Quote: "the only time GOTO is even a little bit acceptable is when the label it links to is on the same page of code."




Also, Hi Hodgey I missed your post last time I was here. Sydney rule!

Hodgey
15
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 22nd Dec 2011 07:29
Quote: "Might as well make it official..."

Grog, there's your new signature.

Quote: "Quote: "the only time GOTO is even a little bit acceptable is when the label it links to is on the same page of code.""

Technically, you could have 80,000 lines of code on the one 'page'.

Quote: "Also, Hi Hodgey I missed your post last time I was here. Sydney rule!"

Absolutely!

I have a question regarding the exit command. In short will the exit command disrupt the stack like the goto command when used to exit a for loop? E.g:



Kevin Picone
22
Years of Service
User Offline
Joined: 27th Aug 2002
Location: Australia
Posted: 22nd Dec 2011 07:36
Quote: "
In short will the exit command disrupt the stack like the goto command when used to exit a for loop
"



Nope. Neither GOTO or EXIT alter the STACK.

Hodgey
15
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 22nd Dec 2011 07:47
Quote: "Nope. Neither GOTO or EXIT alter the STACK."

I'm just reading TDK's How to avoid using gotos tutorial and it says using the goto can alter the stack. Has DBP been updated so that gotos don't alter the stack?

Kevin Picone
22
Years of Service
User Offline
Joined: 27th Aug 2002
Location: Australia
Posted: 22nd Dec 2011 09:24
Quote: "Has DBP been updated so that gotos don't alter the stack?
"


Nope. To me it seems the article is speaking more from a conceptly stand point, than a literal one.

ie.

Quote: "The stack is used for any Dark Basic command which alters program flow. This includes While...Endwhile, Repeat...Until, For...Next, Subroutines and Functions. These are all known as 'conditional jumps' - in other words, they send the PC to another part of the program, but the return condition is saved so there's somewhere to jump back to later."


This is only partially true. Function and Gosub Calls do ideed use the stack, but Loops & decisions don't.

Such assertions largely come from early editions of BASIC (8/16bit mainly), where the stack was indeed the primary mechanic, but not today.

Hodgey
15
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 22nd Dec 2011 11:09
Quote: "This is only partially true. Function and Gosub Calls do ideed use the stack, but Loops & decisions don't. "

Oh ok, thanks Kevin.

Agent
20
Years of Service
User Offline
Joined: 7th Sep 2004
Location: Sydney, Australia
Posted: 22nd Dec 2011 14:55
Hmmm. I would've said that GOTO to escape a condition or a loop definitely causes a stack leak, but then I ran a test that looked like this:

begin:
do
goto out
loop
out:
goto begin

I expected the program to crash from a stack overflow, but it runs for a few minutes on my machine without an increase in memory consumption. It seems to me that we are opening a huge number of loops that are never being closed. It would appear that the stack should be overflowing here.

I can't explain why it isn't, but it looks like Kevin is right.

Very confusing...

TheComet
17
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 22nd Dec 2011 18:18
I have a possible explanation. A loop in machine code is just a jump from the end of the loop to the start of the loop. There is no reason to store any info in the stack.



The above is the same as this if you go down to the machine code level.



When you make subroutines, it's more complex:



Converts to something like this:




Because subroutines and functions are required to return to a specific line, the program adds the last position in the program to the stack before jumping. A loop doesn't require that because it's not expected to return anywhere.

TheComet

nonZero
13
Years of Service
User Offline
Joined: 10th Jul 2011
Location: Dark Empire HQ, Otherworld, Silent Hill
Posted: 22nd Dec 2011 21:27
TheComet has a good point. If you examine Agent's code, you'll notice that the "LOOP" keyword is never encountered. Perhaps during the first pass, DBPro excludes the assembly process for a traditional DO-loop, leaving DO as a label and instead having a series of independent JUMPs between "begin:" and "out:" (which essentially is what is happening. In other words, during precompile, a LOOP must be encountered by the compiler for it to become a valid process.

Take a look at this:


NEXT is never encountered, so FOR will be treated as just a label and the true loop is:



...Just a theory. Might be worth a fuller investigation though.

72 97 112 112 121 32 72 111 108 105 100 97 121 115 32 112 112 108 33

Hodgey
15
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 23rd Dec 2011 00:10
Quote: "I would've said that GOTO to escape a condition or a loop definitely causes a stack leak"

That was my thinking as well. Kevin's response with TheComet's reasoning is a good combination, thanks guys.

Benjamin
21
Years of Service
User Offline
Joined: 24th Nov 2002
Location: France
Posted: 23rd Dec 2011 22:26 Edited at: 23rd Dec 2011 22:34
The stack is rarely changed outside a function (or gosub) call or the initialization of a function, since otherwise it would break references to all of the variables on the stack. In fact in DBP it is more or less only ever changed in these two cases (there may be some specific instances where it needs to store something on the stack to do a particular operation, though it'll be completely transparent to the programmer).

Here's an interesting example of how GOTO doesn't affect the stack, and also why it can be a dangerous command to use:





Support a charitable indie game project!
nonZero
13
Years of Service
User Offline
Joined: 10th Jul 2011
Location: Dark Empire HQ, Otherworld, Silent Hill
Posted: 24th Dec 2011 09:15
Really glad I don't use GOTO/GOSUB now.

lol, more ammunition for Grog's war on GOTO.

72 97 112 112 121 32 72 111 108 105 100 97 121 115 32 112 112 108 33

Hodgey
15
Years of Service
User Offline
Joined: 10th Oct 2009
Location: Australia
Posted: 24th Dec 2011 22:54
Quote: "Here's an interesting example of how GOTO doesn't affect the stack, and also why it can be a dangerous command to use:"

I've got to give you points for imagination there Benjamin. I wouldn't have ever thought to write something like that!

It's reassuring to know that isn't as easily altered as I thought.

Agent
20
Years of Service
User Offline
Joined: 7th Sep 2004
Location: Sydney, Australia
Posted: 1st Jan 2012 08:06 Edited at: 1st Jan 2012 08:16
Lol! I love you, Benjamin. You made me wake up my girlfriend with laughter. She hates me. That's the most awesome broken logic of all time. A GOTO from one function to another! I can't get over it. Hahahaha!

EDIT: 5 minutes later. Still laughing my face off.

Oh boy. Ok, now that I've recovered...

Your explanation on how the stack is related to these commands seems to make a little sense, but I must be missing something since it doesn't seem to completely work. It's been a long time since my DOS game copy-protection cracker days, and I haven't worked in assembler in a good fifteen years.

I thought that any jump in control that expected a return (including loops) involved a stack insertion so that the program would know to where to return. It seems to me that if we can't use the stack to dictate where we're looping back to, when the code hits a LOOP, the only way it can know where to return to is by searching backward through the code until it finds a DO, and going from there. This poses an obvious problem in the case of nested loops, or when there is another jump in control within the loop (like a function call or a GOSUB) which is why I figured the stack is needed for this.

I can't think of any other way this could work? How does the program know where it needs to go back to, if it doesn't store the originating command point on the stack?

Benjamin
21
Years of Service
User Offline
Joined: 24th Nov 2002
Location: France
Posted: 2nd Jan 2012 22:18 Edited at: 2nd Jan 2012 22:22
Quote: "I can't think of any other way this could work? How does the program know where it needs to go back to, if it doesn't store the originating command point on the stack?"


When generating the machine code, the compiler (or more accurately the assembler) manages a list of addresses associated with loops, labels and such, which it later uses in the JMP (jump) instructions (those used at the end of loops), to jump to a fixed address. So the address is stored somewhere, but it's stored at compile-time and it's stored in the code itself.



Support a charitable indie game project!
TheComet
17
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 2nd Jan 2012 22:30


That's very interesting, Benjamin... The endfunction command from function B appears to end the function A instead... I'm not entirely sure why MyVar is written to v though... Here's a modified version of your example showing some strange stuff with local variables:



The first variable prints fine, then for some reason the second variable just prints 0. After that the third variable prints variable 2 from function A, the fourth variable prints variable 3 from function A etc. Why?

TheComet

Benjamin
21
Years of Service
User Offline
Joined: 24th Nov 2002
Location: France
Posted: 2nd Jan 2012 22:54
Quote: "I'm not entirely sure why MyVar is written to v though"


It's the same address, just referenced with a different variable name.

Quote: "The first variable prints fine, then for some reason the second variable just prints 0. After that the third variable prints variable 2 from function A, the fourth variable prints variable 3 from function A etc. Why?
"


For some reason DBPro declares extra stack space in that example, for assigning the values. If you do direct assignment in the declarations it works fine:





Support a charitable indie game project!
nonZero
13
Years of Service
User Offline
Joined: 10th Jul 2011
Location: Dark Empire HQ, Otherworld, Silent Hill
Posted: 3rd Jan 2012 08:55 Edited at: 3rd Jan 2012 08:56
Quote: "If you do direct assignment in the declarations it works fine"


So does that mean it does something like this?

A variable gets declared: PUSH
When a variable gets assigned a value: PUSH (again?)
Then does it MOV(E) the second value to the first and leave the second an empty cyber-carcass?



Excuse my ignorance (I mentioned earlier in this thread that my ASM knowledge is very limited) but that last experiment really left me curious. What's the explanation? Sorry, academic curiosity always bites me hard.

EDIT: I'm going to assume I should make a habbit of directly assigning stuff in my future code.

WLGfx
17
Years of Service
User Offline
Joined: 1st Nov 2007
Location: NW United Kingdom
Posted: 7th Jan 2012 20:35 Edited at: 7th Jan 2012 21:14
Yup, this was worth reading... he he... The joys...

When a function is called with values, they get pushed onto the stack. If the function has variables 'local' to it, then stack space is made for those.

By the looks of the above tests, I'd expect a program to crash if one function didn't declare enough local variables as the next was trying to change.



Untested, but expecting a ginormlious crash because it should compile too.

EDIT: It didn't crash even when I tried this:

Now I'm determined to find a way to get GOTO to crash it by messing up the stack.

Mental arithmetic? Me? (That's for computers) I can't subtract a fart from a plate of beans!
Warning! May contain Nuts!
Latch
18
Years of Service
User Offline
Joined: 23rd Jul 2006
Location:
Posted: 7th Jan 2012 23:29
The ability to jump using goto to a label inside a different function (jumping between functions) must be an error that has crept into DBPro. You can't do that in any BASIC I'm aware of or even in straight C where goto can still be used to mimic some functionality of assembly. Even DBC will complain that the label doesn't exist because it isn't local to the function.

However, there does exist (in C ) setjump and longjump to give the ability to jump between functions. Since DBPro allows a label to be called between functions, what does that imply about the "localness" of the function or even it's need to return to the calling point?

Goto, as stated already, just "moves" to the target. It never stores where it came from so it doesn't need any stack usage.

What does:



do?

If the label can be referenced outside of the function by goto, surely this will eventually crash the program; sort of as a never ending recursive loop.

Enjoy your day.
TheComet
17
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 8th Jan 2012 00:44
Recursive functions always crash at some point when the stack overflows. So yep, that program crashes when you execute it

TheComet

zenassem
21
Years of Service
User Offline
Joined: 10th Mar 2003
Location: Long Island, NY
Posted: 9th Jan 2012 14:38 Edited at: 9th Jan 2012 14:48
Quote: "Recursive functions always crash at some point when the stack overflows. So yep, that program crashes when you execute it
"


Not in the case of tail recursion.
Tail call

Tail-recursive functions are functions in which all recursive calls are tail calls and hence do not build up any deferred operations. For example, the gcd function (shown again below) is tail-recursive. In contrast, the factorial function (also below) is not tail-recursive; because its recursive call is not in tail position, it builds up deferred multiplication operations that must be performed after the final recursive call completes. With a compiler or interpreter that treats tail-recursive calls as jumps rather than function calls, a tail-recursive function such as gcd will execute using constant space. Thus the program is essentially iterative, equivalent to using imperative language control structures like the "for" and "while" loops.

GCD (Tail-recursive)
//INPUT: Integers x, y such that x >= y and y > 0
int gcd(int x, int y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}

Factorial (Not Tail-recursive)
//INPUT: n is an Integer such that n >= 1
int fact(int n)
{
if (n == 1)
return 1;
else
return n * fact(n - 1);
}

The significance of tail recursion is that when making a tail-recursive call, the caller's return position need not be saved on the call stack; when the recursive call returns, it will branch directly on the previously saved return position. Therefore, on compilers that support tail-recursion optimization, tail recursion saves both space and time.

~ZENassem
Latch
18
Years of Service
User Offline
Joined: 23rd Jul 2006
Location:
Posted: 9th Jan 2012 14:58
Quote: "So yep, that program crashes when you execute it "


It shouldn't be recursive because the function isn't calling itself; but it ends up being so. There's a jump out of the function using goto (which shouldn't be allowed) to the main body of the program thus calling the function recursively. This suggests a couple of things:

1. DBPro functions would seem to behave are more like subroutines than actual functions. They should be localized code but apparently they can be jumped into and out of.

2. A discussion about the stack and the results of goto may not be completely accurate or at least there may be a bit of missing information because of the behaviour we're seeing relative to functions.

3. That's one more reason to be careful when choosing to use goto in one's code.

by TheComet:
Quote: "The first variable prints fine, then for some reason the second variable just prints 0. After that the third variable prints variable 2 from function A, the fourth variable prints variable 3 from function A etc. Why?"


Your example adds support to DBPro treating functions more like subroutines than functions. Since function B() is never actually called, I suspect that the memory addresses of the variables under Hack: are actually global. But I'm just guessing. All in all, the behavior is strange. Try something like:



What does that yield?

Enjoy your day.
WLGfx
17
Years of Service
User Offline
Joined: 1st Nov 2007
Location: NW United Kingdom
Posted: 10th Jan 2012 04:44
If function B() had more or less local variables than function A() then when endfunction is reached the stack wouldn't be properly adjusted because it's returning from a different function than what was originally called. So if A() was called x amount of times then there should be a stack error somewhere along the lines.

Interesting this twist on GOTO...

Mental arithmetic? Me? (That's for computers) I can't subtract a fart from a plate of beans!
Warning! May contain Nuts!
Kevin Picone
22
Years of Service
User Offline
Joined: 27th Aug 2002
Location: Australia
Posted: 10th Jan 2012 04:45
Latch,

Quote: "
1. DBPro functions would seem to behave are more like subroutines than actual functions. They should be localized code but apparently they can be jumped into and out of.

2. A discussion about the stack and the results of goto may not be completely accurate or at least there may be a bit of missing information because of the behaviour we're seeing relative to functions.
"


Nah... The local items within a scope (including main), are accessed as offsets from one central point, normally the cpu stack, but you can use whatever you like really. So the compiler isn't referring variables in one fix memory locations, rather it's addressing them as offsets in the current frame (variable table) of local data. When calling a function, we allocate a nice fresh frame of data on the stack (ie. A Variable Table), pass any required data and change control. At this point, the code running inside the function is referring to it's local variables and not the programs locals, only because the stack pointer is pointing to this new position, this new variable table. But if you manually changed stack pointer to point at another function or programs main local frame, then the function is now referencing that scopes data. There's nothing special about the code inside a function.

Clearly this isn't a feature, it's a bug of Dbpro compiler. As allowing users to change controls between functions lets it reference another scopes local data, which is a crash waiting a happen.

Login to post a reply

Server time is: 2024-11-24 01:40:47
Your offset time is: 2024-11-24 01:40:47